home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 October / Chip Ekim 2003.iso / prog / tamsurum / tocom / Security Updates / SQL-MSDE-CriticalUpdate_ENU.msi / Hotfix3 / Files / SecurityHotfix.sql < prev    next >
Encoding:
Text File  |  2002-09-16  |  380.9 KB  |  12,255 lines

  1. dump tran master with no_log
  2. go
  3.  
  4. set ANSI_NULLS off
  5. go
  6.  
  7. use master
  8. go
  9.  
  10. if exists (select * from sysobjects
  11.         where name = 'xp_createqueue')
  12.     execute dbo.sp_dropextendedproc 'xp_createqueue'
  13. go
  14.  
  15. if exists (select * from sysobjects
  16.         where name = 'xp_deletequeue')
  17.     execute dbo.sp_dropextendedproc 'xp_deletequeue'
  18. go
  19.  
  20. if exists (select * from sysobjects
  21.         where name = 'xp_intersectbitmaps')
  22.     execute dbo.sp_dropextendedproc 'xp_intersectbitmaps'
  23. go
  24.  
  25. dump tran master with no_log
  26. go
  27. checkpoint
  28. go
  29. use master
  30. go
  31.  
  32. if exists (select * from sysobjects
  33.         where name = N'xp_SetSQLSecurity')
  34.     execute dbo.sp_dropextendedproc N'xp_SetSQLSecurity'
  35. go
  36.  
  37. print N'Creating extended stored procedure xp_SetSQLSecurity'
  38. exec sp_addextendedproc N'xp_SetSQLSecurity',N'xpstar.dll'
  39. go
  40.  
  41. dump tran master with no_log
  42. go
  43. checkpoint
  44. go
  45.  
  46. -------------------------------------------------------------------------------
  47. --. qfe360814.sql
  48. -------------------------------------------------------------------------------
  49.  
  50. dump tran master with no_log
  51. go
  52.  
  53. exec dbo.sp_configure 'allow updates',1
  54. go
  55. reconfigure with override
  56. go
  57.  
  58. set ANSI_NULLS off
  59.  
  60. exec sp_MS_upd_sysobj_category 1
  61. go
  62.  
  63. --------------------------------------------------------------------------------
  64. --.    System objects (replsys.sql)
  65. --------------------------------------------------------------------------------
  66. if exists (select * from sysobjects
  67.     where type = 'FN'
  68.     and name = N'fn_escapecmdshellsymbols' )
  69.     drop function system_function_schema.fn_escapecmdshellsymbols
  70.  
  71. raiserror('Creating function fn_escapecmdshellsymbols', 0,1) with nowait
  72. go
  73. --
  74. -- Name: fn_escapecmdshellsymbols
  75. --
  76. -- Descriptions: This function returns an escaped version of a given string
  77. --               with carets ('^') added in front of all the special 
  78. --               command shell symbols. In the W2K online help (Start->
  79. --               Help->Index->Command Reference->Command Symbols...), the 
  80. --               following symbols are listed as special command symbols:
  81. --                 (N'%', N'<', N'>', N'|', N'&', N'(', N')', N'^', N'"')
  82. --
  83. -- Parameter: @command_string nvarchar(4000)
  84. -- 
  85. -- Example: select fn_escapecmdshellsymbols(N'The % quick < brown > dog | jumps & over ( the ) lazy ^ fox.') 
  86. --             will return 
  87. --    
  88. --    The ^% quick ^< brown ^> dog ^| jumps ^& over ^( the ^) lazy ^^ fox
  89. --
  90. -- Security: This function is granted to public
  91. --
  92. create function system_function_schema.fn_escapecmdshellsymbols(
  93.     @command_string nvarchar(4000)
  94.     ) returns nvarchar(4000)
  95. as
  96. begin
  97.     declare @escaped_command_string nvarchar(4000),
  98.             @curr_char nvarchar(1),
  99.             @curr_char_index int    
  100.     select @escaped_command_string = N'',
  101.            @curr_char = N'', 
  102.            @curr_char_index = 1
  103.     while @curr_char_index <= len(@command_string)
  104.     begin
  105.         select @curr_char = substring(@command_string, @curr_char_index, 1) 
  106.         if @curr_char in (N'%', N'<', N'>', N'|', N'&', N'(', N')', N'^', N'"')
  107.         begin
  108.             select @escaped_command_string = @escaped_command_string + N'^'
  109.         end
  110.         select @escaped_command_string = @escaped_command_string + @curr_char
  111.         select @curr_char_index = @curr_char_index + 1 
  112.     end
  113.     return @escaped_command_string
  114. end
  115. go
  116. grant execute on system_function_schema.fn_escapecmdshellsymbols to public
  117.  
  118. if exists (select * from sysobjects
  119.     where type = 'FN'
  120.     and name = N'fn_escapecmdshellsymbolsremovequotes' )
  121.     drop function system_function_schema.fn_escapecmdshellsymbolsremovequotes
  122.  
  123. raiserror('Creating function fn_escapecmdshellsymbolsremovequotes', 0,1) with nowait
  124. go
  125. --
  126. -- Name: fn_escapecmdshellsymbolsremovequotes
  127. --
  128. -- Descriptions: The only difference between this function and 
  129. --               fn_escapecmdshellsymbols is that "'s are removed from the 
  130. --               resulting command line.
  131. --
  132. -- Parameter: @command_string nvarchar(4000)
  133. -- 
  134. -- Security: This function is granted to public
  135. --
  136. create function system_function_schema.fn_escapecmdshellsymbolsremovequotes(
  137.     @command_string nvarchar(4000)
  138.     ) returns nvarchar(4000)
  139. as
  140. begin
  141.     declare @escaped_command_string nvarchar(4000),
  142.             @curr_char nvarchar(1),
  143.             @curr_char_index int    
  144.     select @escaped_command_string = N'',
  145.            @curr_char = N'', 
  146.            @curr_char_index = 1
  147.     while @curr_char_index <= len(@command_string)
  148.     begin
  149.         select @curr_char = substring(@command_string, @curr_char_index, 1) 
  150.         if @curr_char in (N'%', N'<', N'>', N'|', N'&', N'(', N')', N'^')
  151.         begin
  152.             select @escaped_command_string = @escaped_command_string + N'^'
  153.         end
  154.  
  155.         if @curr_char <> '"'
  156.         begin
  157.             select @escaped_command_string = @escaped_command_string + @curr_char
  158.         end
  159.         select @curr_char_index = @curr_char_index + 1 
  160.     end
  161.     return @escaped_command_string
  162. end
  163. go
  164. grant execute on system_function_schema.fn_escapecmdshellsymbolsremovequotes to public
  165.  
  166. if exists (select * from sysobjects
  167.      where type = 'P '
  168.             and name = 'sp_MSget_file_existence')
  169.      drop procedure sp_MSget_file_existence
  170. go
  171.  
  172. print ''
  173. print 'Creating procedure sp_MSget_file_existence'
  174. go
  175. create procedure sp_MSget_file_existence (
  176. @filename nvarchar(260),
  177. @exists bit = 0 output
  178. )
  179. AS
  180.     SET NOCOUNT ON
  181.  
  182.     DECLARE @command nvarchar(512)
  183.     DECLARE @retcode int
  184.     declare @echo_text nvarchar(20)
  185.  
  186.     select @echo_text = 'file_exists'
  187.  
  188.     /*
  189.     ** The return code from xp_cmdshell is not a reliable way to check whether the file exists or
  190.     ** not. It is always 0 on Win95 as long as xp_cmdshell succeeds.
  191.     */  
  192.  
  193.     select @command = N'if exist "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + N'" echo ' + @echo_text
  194.  
  195.     create table #text_ret(cmdoutput nvarchar(20) collate database_default null)
  196.  
  197.     insert into #text_ret exec @retcode = master..xp_cmdshell @command
  198.     if @@error <> 0 or @retcode <> 0
  199.         return 1
  200.  
  201.     if exists (select * from #text_ret where ltrim(rtrim(cmdoutput)) = @echo_text)
  202.         select @exists = 1
  203.     else 
  204.         select @exists = 0
  205.  
  206.     drop table #text_ret
  207. go
  208. EXEC dbo.sp_MS_marksystemobject sp_MSget_file_existence
  209. GO
  210.  
  211. if exists (select * from sysobjects
  212.     where type = 'P '
  213.             and name = 'sp_replicationoption')
  214.     drop procedure sp_replicationoption
  215. go
  216.  
  217. raiserror('Creating procedure sp_replicationoption', 0,1)
  218. go
  219.  
  220. CREATE PROCEDURE sp_replicationoption (
  221. @optname        sysname,
  222. @value            nvarchar(5),
  223. @security_mode    int = 0,
  224. @login            sysname = 'sa',
  225. @password        sysname = NULL,
  226. @reserved       nvarchar(20) = NULL
  227. )
  228. AS
  229.     DECLARE @optbit bit
  230.     DECLARE @osql_path nvarchar(260)
  231.     DECLARE @osql_cmd1 nvarchar (255)
  232.     DECLARE @osql_cmd_full nvarchar (255)
  233.     DECLARE @osql_for_nt int
  234.  
  235.     DECLARE @install_path nvarchar (255)
  236.  
  237.     DECLARE @retcode int
  238.     DECLARE @undo_install nvarchar(20)
  239.     DECLARE @no_scripts nvarchar(10)
  240.     DECLARE @platform_nt binary
  241.     
  242.     SELECT @platform_nt = 0x1
  243.  
  244.     if    is_srvrolemember('sysadmin') <> 1
  245.         BEGIN
  246.             RAISERROR (15232, 14, -1)
  247.             RETURN (1)
  248.         END
  249.     
  250.     SELECT @no_scripts = 'no_scripts'
  251.  
  252.     SELECT @undo_install = 'undo_install'
  253.  
  254.     IF db_name() <> 'master'
  255.     BEGIN
  256.         RAISERROR(5001, 16,-1)
  257.         GOTO FAILURE
  258.     END
  259.  
  260.     IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('transactional','merge')
  261.     BEGIN
  262.         RAISERROR(21014, 16, -1)
  263.         GOTO FAILURE
  264.     END
  265.     IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true','false')
  266.     BEGIN
  267.         RAISERROR(14137,16,-1)
  268.         GOTO FAILURE
  269.     END
  270.     
  271.     IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  272.         SELECT @optbit = 1
  273.     ELSE
  274.         SELECT @optbit = 0
  275.  
  276.     /*
  277.     ** Check if the option is set as required already
  278.     */
  279.     IF @reserved <> @undo_install AND EXISTS (SELECT * FROM MSreplication_options
  280.         WHERE    optname  = @optname
  281.         AND        value = @optbit)
  282.     BEGIN
  283.         IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  284.             RAISERROR (21015, 10, -1, @optname)        
  285.         ELSE
  286.             RAISERROR (21016, 10, -1, @optname)
  287.         GOTO FAILURE
  288.     END
  289.  
  290.     /* Install replication */
  291.     IF @optbit = 1
  292.     BEGIN
  293.  
  294.         IF LOWER(@reserved collate SQL_Latin1_General_CP1_CS_AS) = @no_scripts
  295.             GOTO NO_SCRIPTS
  296.  
  297.         -- Set the flag for platform
  298.         IF (( platform() & @platform_nt = @platform_nt ))
  299.             SELECT @osql_for_nt = 1
  300.         ELSE
  301.             SELECT @osql_for_nt = 0
  302.  
  303.         /* 
  304.         ** Get installation path -- osql client (TOOLS) path
  305.         */
  306.         EXECUTE @retcode = master.dbo.sp_MSgettools_path @osql_path OUTPUT
  307.         IF ( @@ERROR <> 0 ) OR ( @retcode <> 0 ) or ( @osql_path is NULL ) or ( @osql_path = '' )
  308.         BEGIN
  309.             GOTO FAILURE       
  310.         END
  311.  
  312.         /* 
  313.         ** Get installation path -- instance specific (INSTALL) directory
  314.         */
  315.         exec @retcode = master.dbo.sp_MSget_setup_paths
  316.             @sql_path = @install_path output
  317.         IF @@ERROR<> 0 OR @retcode <> 0 or @install_path is NULL or @install_path=''
  318.             BEGIN
  319.                 GOTO FAILURE       
  320.             END
  321.  
  322.         /* 
  323.         ** Install replcom.sql and repltran.sql
  324.         */
  325.         IF @security_mode = 1
  326.         begin
  327.             SELECT @osql_cmd1 = '"' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -E ' 
  328.             if serverproperty('instancename') is not null
  329.                 SELECT @osql_cmd1 = @osql_cmd1 + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
  330.         end
  331.         ELSE
  332.             -- cannot specify -S w/ -E for local execution, SID does not map
  333.             SELECT @osql_cmd1 = '"' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U"' + fn_escapecmdshellsymbols(@login) collate database_default + '" -P"' + 
  334.                 fn_escapecmdshellsymbols(isnull(@password,'')) collate database_default + '" -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
  335.  
  336.         select @osql_cmd1 = @osql_cmd1 + '-l30 -t30 '
  337.  
  338.         -- Install replcom.sql 
  339.         -- Only apply replcom.sql if it was not applied before.
  340.         -- '-b' option will make osql stop at errors and return error code
  341.         -- We must use this option.
  342.         IF NOT EXISTS (SELECT * FROM MSreplication_options
  343.             WHERE value = 1)
  344.         BEGIN
  345.             -- Initialize the Command
  346.             IF (@osql_for_nt = 1)
  347.                 SELECT @osql_cmd_full = '" '
  348.             ELSE
  349.                 SELECT @osql_cmd_full = ' '
  350.  
  351.             SELECT @osql_cmd_full = @osql_cmd_full +
  352.                 @osql_cmd1 + 
  353.                 ' -dmaster' +  ' -b ' +
  354.                 ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replcom.sql"' + 
  355.                 ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replcom.out"' 
  356.  
  357.             IF (@osql_for_nt = 1)
  358.                 SELECT @osql_cmd_full = @osql_cmd_full + ' "'
  359.  
  360.             EXEC @retcode = master..xp_cmdshell @osql_cmd_full
  361.             IF @@ERROR<> 0 OR @retcode <> 0
  362.             BEGIN
  363.                 RAISERROR (14113, 16, -1, @osql_cmd_full, 'replcom.out')
  364.                 GOTO UNDO_INSTALL     
  365.             END
  366.         END
  367.  
  368.         IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'transactional'
  369.         BEGIN
  370.             -- Install repltran.sql
  371.             IF (@osql_for_nt = 1)
  372.                 SELECT @osql_cmd_full = '" '
  373.             ELSE
  374.                 SELECT @osql_cmd_full = ' '
  375.  
  376.             SELECT @osql_cmd_full = @osql_cmd_full +
  377.                 @osql_cmd1 + 
  378.                 ' -dmaster' +  ' -b ' +
  379.                 ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\repltran.sql"' + 
  380.                 ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\repltran.out"' 
  381.  
  382.             IF (@osql_for_nt = 1)
  383.                 SELECT @osql_cmd_full = @osql_cmd_full + ' "'
  384.  
  385.             EXEC @retcode = master..xp_cmdshell @osql_cmd_full
  386.             IF @@ERROR<> 0 OR @retcode <> 0
  387.             BEGIN
  388.                 RAISERROR (14113, 16, -1, @osql_cmd_full, 'repltran.out')
  389.                 GOTO UNDO_INSTALL     
  390.             END
  391.  
  392.         END
  393.  
  394.         IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge'
  395.         BEGIN
  396.             -- Install replmerg.sql 
  397.             IF (@osql_for_nt = 1)
  398.                 SELECT @osql_cmd_full = '" '
  399.             ELSE
  400.                 SELECT @osql_cmd_full = ' '
  401.  
  402.             SELECT @osql_cmd_full = @osql_cmd_full +
  403.                 @osql_cmd1 + 
  404.                 ' -dmaster' + ' -b ' +
  405.                 ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replmerg.sql"' + 
  406.                 ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\replmerg.out"' 
  407.             
  408.             IF (@osql_for_nt = 1)
  409.                 SELECT @osql_cmd_full = @osql_cmd_full + ' "'
  410.  
  411.             EXEC @retcode = master..xp_cmdshell @osql_cmd_full 
  412.             
  413.             IF  @@ERROR<> 0 OR @retcode <> 0
  414.             BEGIN
  415.                 RAISERROR (14113, 16, -1, @osql_cmd_full, 'replmerg.out')
  416.                 GOTO UNDO_INSTALL     
  417.             END
  418.         END
  419.  
  420. NO_SCRIPTS:
  421.  
  422.         UPDATE MSreplication_options SET value = @optbit
  423.             WHERE optname = @optname
  424.         IF @@ERROR <> 0 
  425.         BEGIN
  426.             GOTO UNDO_INSTALL    
  427.         END
  428.  
  429.     END
  430.     /* Uninstall replication */
  431.     ELSE
  432.     BEGIN
  433.  
  434.         /* 
  435.         ** Make sure no distributor installed before dropping 
  436.         ** replication stored procedures
  437.         */
  438.         IF EXISTS (SELECT * FROM master..sysservers
  439.               WHERE  srvstatus & 8 <> 0)
  440.         BEGIN
  441.             RAISERROR (21021, 16, -1)
  442.             RETURN(1)
  443.         END
  444.  
  445.         UPDATE MSreplication_options SET value = @optbit
  446.             WHERE optname = @optname
  447.         IF @@ERROR <> 0 
  448.         BEGIN
  449.             GOTO FAILURE
  450.         END
  451.  
  452.         /* 
  453.         *********** Do not drop replication stored procs anymore.
  454.  
  455.         IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'transactional'
  456.         BEGIN
  457.             if exists (select * from sysobjects
  458.                 where type = 'P '
  459.                         and name = 'sp_MSdrop_repltran')
  460.             begin
  461.                 exec @retcode = dbo.sp_MSdrop_repltran
  462.                 if @@ERROR = 0 and @retcode = 0
  463.                     drop procedure sp_MSdrop_repltran
  464.             end
  465.         END
  466.  
  467.         IF LOWER(@optname collate SQL_Latin1_General_CP1_CS_AS) = 'merge'
  468.         BEGIN
  469.             if exists (select * from sysobjects
  470.                 where type = 'P '
  471.                         and name = 'sp_MSdrop_replmerg')
  472.             begin
  473.                 exec @retcode = dbo.sp_MSdrop_replmerg
  474.                 if @@ERROR = 0 and @retcode = 0
  475.                     drop procedure sp_MSdrop_replmerg
  476.             end
  477.         END
  478.  
  479.         IF NOT EXISTS (SELECT * FROM MSreplication_options
  480.             WHERE value = 1)
  481.         BEGIN
  482.             if exists (select * from sysobjects
  483.                 where type = 'P '
  484.                         and name = 'sp_MSdrop_replcom')
  485.             begin
  486.                 exec @retcode = dbo.sp_MSdrop_replcom
  487.                 if @@ERROR = 0 and @retcode = 0
  488.                     drop procedure sp_MSdrop_replcom
  489.             end
  490.         END
  491.  
  492.         */
  493.     END
  494.  
  495.     RETURN(0)
  496.  
  497. UNDO_INSTALL:
  498.     /* This is needed to drop the stored procedures that were created. */
  499.     EXEC dbo.sp_replicationoption @optname =  @optname, 
  500.         @value = 'false', @reserved = @undo_install
  501.  
  502. FAILURE:
  503.     RETURN(1)
  504. GO
  505. exec dbo.sp_MS_marksystemobject sp_replicationoption
  506. go
  507. grant execute on dbo.sp_replicationoption to public
  508.  
  509. if exists (select * from sysobjects 
  510.         where name = 'sp_vupgrade_replication' 
  511.                 and type = 'P')
  512.       drop procedure sp_vupgrade_replication
  513. go
  514. raiserror('Creating procedure sp_vupgrade_replication', 0,1)
  515. GO
  516.  
  517. create procedure sp_vupgrade_replication ( @login sysname = N'sa', @password sysname = N'', @ver_old int = 517, @force_remove tinyint = 0, @security_mode bit = 0 )
  518. as
  519. begin
  520. /* 
  521.  * Dispatcher proc for handling schema and metadata changes during setup initiated version upgrade 
  522.  * for replication components. Any schema changes to replication system tables may require modifications 
  523.  * here to maintain upgrade path. All modifications called in these procs are within "if exists" checks
  524.  * making them repeatable for debugging and to support incremental upgrades (e.g. Beta 1 to Beta 2 to RTM)
  525.  * 
  526.  * If server is a distributor, run new instdist.sql against all distribution dbs.
  527.  *
  528.  * This proc gets called by setup at the end of an install over an existing version.
  529. */
  530.  
  531.     set nocount on 
  532.  
  533.     declare @dbname sysname
  534.     declare @has_dbaccess bit
  535.     declare @install_path nvarchar(255)
  536.     declare @osql_path nvarchar(260)
  537.     declare @osql_cmd nvarchar(512)
  538.     declare @osql_for_nt int
  539.     declare @retcode int
  540.     declare @platform_nt binary
  541.     declare @db_distbit int
  542.     declare @ver_min             int
  543.  
  544.     select @db_distbit = 16
  545.     select @platform_nt = 0x1
  546.  
  547.     -- raiserror('sp_vupgrade_replication', 0,1) with nowait
  548.  
  549.     /*
  550.      * obsolete check; ver check was to prevent repl upgrade from
  551.      * versions prior to SQL7.0 Beta 3; check is removed by setting @ver_min = -1
  552.     */
  553.     select @ver_min= -1 -- change if later wish to support a minimum upgrade version
  554.     if ( @ver_old < @ver_min ) or ( @force_remove = 1 )
  555.         exec dbo.sp_removesrvreplication
  556.     else
  557.     begin
  558.  
  559.         /* 
  560.          * always need to run instdist.sql to update distribution databases on a distributor
  561.          * setup must restart in non-single user mode so we can shell out to run instdist.sql scripts
  562.         */
  563.         if exists( select * from master..sysdatabases where category & @db_distbit = @db_distbit )
  564.         begin
  565.  
  566.             /* 
  567.             ** Get installation path -- osql client (TOOLS) path
  568.             */
  569.             EXECUTE @retcode = master.dbo.sp_MSgettools_path @osql_path OUTPUT
  570.             IF ( @@ERROR <> 0 ) OR ( @retcode <> 0 ) or ( @osql_path is NULL ) or ( @osql_path = '' )
  571.             BEGIN
  572.                 RETURN (1)
  573.             END
  574.  
  575.             /* 
  576.             ** Get installation path -- instance specific (INSTALL) directory
  577.             */
  578.             exec @retcode = master.dbo.sp_MSget_setup_paths
  579.                 @sql_path = @install_path output
  580.             IF @@ERROR<> 0 OR @retcode <> 0 or @install_path is NULL or @install_path=N''
  581.             BEGIN
  582.                 RETURN (1)
  583.             END
  584.  
  585.             -- Set the flag for platform
  586.             if (( platform() & @platform_nt = @platform_nt ))
  587.                 select @osql_for_nt = 1
  588.             else
  589.                 select @osql_for_nt = 0
  590.  
  591.             declare cur_distdb CURSOR LOCAL FAST_FORWARD for 
  592.                 select name, has_dbaccess(name) from master..sysdatabases 
  593.                     where category & @db_distbit = @db_distbit
  594.                 for read only
  595.             
  596.             open cur_distdb
  597.             fetch cur_distdb into @dbname, @has_dbaccess
  598.             while ( @@fetch_status <> -1 )
  599.             begin
  600.  
  601.                 -- if distribution database is available upgrade it; if offline error out
  602.                 if ( @has_dbaccess = 1 )
  603.                 begin
  604.                     raiserror( 21374, 0, 1, @dbname) with nowait
  605.  
  606.                     /*
  607.                      * Format osql cmd line appropriate for security mode and OS to run instdist.sql against
  608.                      * each distribution database. Instdist.sql will recompile procs and will also do some
  609.                      * schema and metadata upgrade of changed replication tables. Query timeout increased to
  610.                      * make enough time for alter tables in instdist.sql run for upgrade to complete.
  611.                     */
  612.                     if ( @osql_for_nt = 1 )
  613.                         select @osql_cmd = N'" "'
  614.                     else
  615.                         select @osql_cmd = N' "'
  616.                     
  617.                     -- Cannot specify -S w/ -E for local execution, SID does not map (nofix)
  618.                     if ( @security_mode = 1 and @osql_for_nt = 1 )
  619.                     begin
  620.                         select @osql_cmd = @osql_cmd + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -E '
  621.                         if serverproperty('instancename') is not null
  622.                             select @osql_cmd = @osql_cmd + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
  623.                     end
  624.                     else
  625.                         select @osql_cmd = @osql_cmd + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U' + fn_escapecmdshellsymbols(isnull(@login, N'sa')) collate database_default + ' -P' + fn_escapecmdshellsymbols(isnull(@password, N'')) collate database_default + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
  626.  
  627.                     select @osql_cmd = @osql_cmd + ' -l30 -t120 '
  628.                     select @osql_cmd = @osql_cmd + ' -b ' + ' -d' + fn_escapecmdshellsymbols(@dbname) collate database_default
  629.                     select @osql_cmd = @osql_cmd +    ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.sql"' + 
  630.                                                     ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.out"'            
  631.  
  632.                     if (@osql_for_nt = 1)
  633.                         select @osql_cmd = @osql_cmd + ' "'
  634.  
  635.                      exec @retcode = master..xp_cmdshell @osql_cmd
  636.                     if @retcode <> 0 or @@error <> 0
  637.                     begin
  638.                         raiserror (14113, 16, -1, @osql_cmd, 'instdist.out')
  639.                     end
  640.  
  641.                     /*
  642.                      * Process schema and metadata changes for each distribution database
  643.                     */
  644.  
  645.                     select @dbname = quotename(@dbname)
  646.                     exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_distdb')
  647.                     if @@error <> 0
  648.                         return(1)
  649.                 end
  650.                 else
  651.                 begin
  652.                     /* Report informational message stating distribution
  653.                     ** database is not accessible.
  654.                     */
  655.                     raiserror( 21378, 10, 1, @dbname) with nowait
  656.                 end
  657.                 
  658.                 fetch next from cur_distdb into @dbname, @has_dbaccess
  659.             end
  660.             close cur_distdb
  661.             deallocate cur_distdb
  662.         end
  663.  
  664.     
  665.         -- Update subscription database schema
  666.         exec @retcode = dbo.sp_vupgrade_subscription_databases
  667.         if @retcode <> 0 or @@error <> 0
  668.             return (1)
  669.  
  670.  
  671.     end
  672.  
  673.     return (0)
  674.  
  675. end
  676. go
  677. exec dbo.sp_MS_marksystemobject sp_vupgrade_replication
  678. go
  679.  
  680. if exists (select * from sysobjects 
  681.         where name = 'sp_MScopysnapshot' 
  682.                 and type = 'P')
  683.       drop procedure sp_MScopysnapshot
  684. go
  685.  
  686. raiserror('Creating procedure sp_MScopysnapshot', 0,1)
  687. go
  688. CREATE PROCEDURE sp_MScopysnapshot (
  689.     @source_folder           nvarchar(255),
  690.     @destination_folder      nvarchar(255)
  691.     )
  692. AS
  693. BEGIN
  694.     SET NOCOUNT ON
  695.     DECLARE @directory_exists bit    
  696.     DECLARE @ftporuncdir      nvarchar(5)
  697.     DECLARE @pubdir           nvarchar(255)
  698.     DECLARE @timestampdir     nvarchar(255)
  699.     DECLARE @bslashindex      int
  700.     DECLARE @bslashindex2     int
  701.     DECLARE @bslashcounter    int
  702.     DECLARE @command          nvarchar(1000)
  703.     DECLARE @retcode          int
  704.     DECLARE @platform_nt      bit
  705.  
  706.     IF platform() & 0x1 = 0x1
  707.         SELECT @platform_nt = 1
  708.     ELSE
  709.         SELECT @platform_nt = 0
  710.  
  711.     -- If @source_folder is NULL then either the snapshot has not been 
  712.     -- generated or it has been cleaned up
  713.     IF @source_folder IS NULL OR @source_folder = N''
  714.     BEGIN
  715.         RAISERROR(21289, 16, -1)
  716.         RETURN (1)
  717.     END
  718.  
  719.     -- Make sure that the @destination folder is not null
  720.     IF @destination_folder IS NULL OR
  721.        @destination_folder = N''
  722.     BEGIN
  723.         RAISERROR(21287, 16, -1)      
  724.         RETURN (1)
  725.     END
  726.  
  727.     -- Append backslash to @destination_folder if it is not 
  728.     -- there already
  729.     IF SUBSTRING(@destination_folder, LEN(@destination_folder), 1) <> N'\'
  730.     BEGIN
  731.         SELECT @destination_folder = @destination_folder + N'\'
  732.     END
  733.  
  734.     -- Check if the destination folder exists 
  735.     EXEC sp_MSget_file_existence @destination_folder, @directory_exists OUTPUT
  736.     IF @directory_exists = 0
  737.     BEGIN
  738.         RAISERROR(21287, 16, -1)      
  739.         RETURN (1)
  740.     END    
  741.     
  742.     -- Parse out the last three components in the source folder 
  743.     -- Note that the source_folder must have a trailing backslash
  744.     SELECT @bslashindex = 1
  745.     SELECT @bslashindex2 = 1
  746.     SELECT @bslashcounter = 0
  747.     WHILE (@bslashindex <> 0)
  748.     BEGIN
  749.         SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex + 1)
  750.         SELECT @bslashcounter = @bslashcounter + 1
  751.         IF @bslashcounter > 4
  752.         BEGIN
  753.             SELECT @bslashindex2 = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1)
  754.         END    
  755.     END  
  756.  
  757.     SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1)
  758.     SELECT @ftporuncdir = SUBSTRING(@source_folder, @bslashindex2 + 1, @bslashindex - @bslashindex2 - 1)
  759.     SELECT @bslashindex2 = @bslashindex
  760.  
  761.     SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1)
  762.     SELECT @pubdir = SUBSTRING(@source_folder, @bslashindex2 + 1, @bslashindex - @bslashindex2 - 1) 
  763.     SELECT @bslashindex2 = @bslashindex
  764.  
  765.     SELECT @bslashindex = CHARINDEX(N'\', @source_folder, @bslashindex2 + 1)
  766.     SELECT @timestampdir = SUBSTRING(@source_folder, @bslashindex2 + 1, @bslashindex - @bslashindex2 - 1) 
  767.     SELECT @bslashindex2 = @bslashindex
  768.         
  769.     -- Create the subdirectory structure underneath the specified snapshot
  770.     -- folder. Ignore errors for now, we will check whether the directory 
  771.     -- is successfully created later on.
  772.  
  773.     -- Don't suppress output from xp_cmdshell so user knows what's going on
  774.     -- in case something goes wrong 
  775.     SELECT @destination_folder = @destination_folder + @ftporuncdir + '\'
  776.     SELECT @command = 'mkdir "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"'
  777.     IF (@platform_nt = 1)
  778.         SELECT @command = '" ' + @command + ' "'
  779.     EXEC master..xp_cmdshell @command
  780.     
  781.     SELECT @destination_folder = @destination_folder + @pubdir + '\'
  782.     SELECT @command = 'mkdir "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate  database_default + '"'
  783.     IF (@platform_nt = 1)
  784.         SELECT @command = '" ' + @command + ' "'
  785.     EXEC master..xp_cmdshell @command
  786.  
  787.     SELECT @destination_folder = @destination_folder + @timestampdir + '\'
  788.     SELECT @command = 'mkdir "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"'
  789.     IF (@platform_nt = 1)
  790.         SELECT @command = '" ' + @command + ' "'
  791.     EXEC master..xp_cmdshell @command
  792.  
  793.     -- Check if the real destination folder exists
  794.     EXEC sp_MSget_file_existence @destination_folder, @directory_exists OUTPUT
  795.     IF @directory_exists = 0
  796.     BEGIN
  797.         RAISERROR(21288, 16, -1)
  798.         RETURN (1)
  799.     END
  800.  
  801.     -- Do the actual copying
  802.     SELECT @command = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@source_folder) collate database_default + '*.*" "' + fn_escapecmdshellsymbolsremovequotes(@destination_folder) collate database_default + '"'    
  803.     IF (@platform_nt = 1)
  804.         SELECT @command = '" ' + @command + ' "'
  805.     
  806.     EXEC @retcode = master..xp_cmdshell @command
  807.     
  808.     IF @retcode <> 0
  809.         RETURN (1)
  810.     ELSE
  811.         RETURN (0)
  812. END
  813. go
  814. EXEC dbo.sp_MS_marksystemobject sp_MScopysnapshot
  815. go
  816.  
  817. if exists (select * from sysobjects 
  818.         where name = 'sp_copymergesnapshot' 
  819.                 and type = 'P')
  820.       drop procedure sp_copymergesnapshot
  821. go
  822.  
  823. raiserror('Creating procedure sp_copymergesnapshot', 0,1)
  824. go
  825. CREATE PROCEDURE sp_copymergesnapshot (
  826.     @publication          sysname,
  827.     @destination_folder   nvarchar(255)
  828.     )
  829. AS
  830. BEGIN
  831.     SET NOCOUNT ON
  832.     DECLARE @retcode       int
  833.     DECLARE @source_folder nvarchar(255)
  834.     SELECT @retcode = 0
  835.     
  836.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  837.     IF @@ERROR <> 0 OR @retcode <> 0
  838.         RETURN (1)
  839.  
  840.     CREATE TABLE #snapshot_folders
  841.     (
  842.         id              int identity, 
  843.         snapshot_folder nvarchar(255) collate database_default
  844.     )
  845.     IF @@ERROR <> 0
  846.     BEGIN
  847.         RETURN 1
  848.     END
  849.  
  850.     INSERT INTO #snapshot_folders
  851.     EXEC @retcode = sp_browsemergesnapshotfolder @publication = @publication
  852.     IF @retcode <> 0 OR @@ERROR <> 0
  853.     BEGIN
  854.         GOTO Failure
  855.     END
  856.     
  857.     SELECT @source_folder = (select top 1 snapshot_folder FROM #snapshot_folders ORDER BY id ASC)
  858.     IF @@ERROR <> 0
  859.     BEGIN
  860.         GOTO Failure
  861.     END        
  862.     SET ROWCOUNT 0    
  863.  
  864.     EXEC @retcode = sp_MScopysnapshot @source_folder,
  865.                                       @destination_folder
  866.     IF @retcode <> 0 OR @@ERROR <> 0 
  867.     BEGIN
  868.         GOTO Failure
  869.     END
  870.  
  871.     DROP TABLE #snapshot_folders
  872.     RETURN 0
  873. Failure:
  874.     SET ROWCOUNT 0    
  875.     DROP TABLE #snapshot_folders        
  876.     RETURN 1
  877. END
  878. GO
  879. EXEC dbo.sp_MS_marksystemobject sp_copymergesnapshot
  880. go
  881. grant execute on dbo.sp_copymergesnapshot to public
  882. go
  883.  
  884. if exists (select * from sysobjects 
  885.         where name = 'sp_copysnapshot' 
  886.                 and type = 'P')
  887.       drop procedure sp_copysnapshot
  888. go
  889.  
  890. raiserror('Creating procedure sp_copysnapshot', 0,1)
  891. go
  892. CREATE PROCEDURE sp_copysnapshot (
  893.     @publication        sysname,
  894.     @destination_folder nvarchar(255),
  895.     @subscriber         sysname = NULL,
  896.     @subscriber_db      sysname = NULL
  897.     )
  898. AS
  899. BEGIN
  900.     SET NOCOUNT ON
  901.     DECLARE @retcode       int
  902.     DECLARE @source_folder nvarchar(255)
  903.     SELECT @retcode = 0
  904.     
  905.  
  906.     EXEC @retcode = dbo.sp_MSreplcheck_publish
  907.     IF @@ERROR <> 0 OR @retcode <> 0
  908.         RETURN (1)
  909.  
  910.     CREATE TABLE #snapshot_folders
  911.     (
  912.         id              int identity,
  913.         snapshot_folder nvarchar(255) collate database_default
  914.     )
  915.     IF @@ERROR <> 0
  916.     BEGIN
  917.         RETURN 1
  918.     END
  919.  
  920.     INSERT INTO #snapshot_folders
  921.     EXEC @retcode = sp_browsesnapshotfolder @publication = @publication,
  922.                                             @subscriber = @subscriber,
  923.                                             @subscriber_db = @subscriber_db
  924.     IF @retcode <> 0 OR @@ERROR <> 0
  925.     BEGIN
  926.         GOTO Failure
  927.     END
  928.  
  929.     SELECT @source_folder = (select top 1 snapshot_folder FROM #snapshot_folders ORDER BY id)
  930.     IF @@ERROR <> 0
  931.     BEGIN
  932.         GOTO Failure
  933.     END        
  934.     SET ROWCOUNT 0
  935.  
  936.     EXEC @retcode = sp_MScopysnapshot @source_folder,
  937.                                       @destination_folder
  938.     IF @retcode <> 0 OR @@ERROR <> 0 
  939.     BEGIN
  940.         GOTO Failure
  941.     END
  942.  
  943.     DROP TABLE #snapshot_folders
  944.     RETURN 0
  945. Failure:
  946.     SET ROWCOUNT 0
  947.     DROP TABLE #snapshot_folders        
  948.     RETURN 1
  949. END
  950. GO
  951. EXEC dbo.sp_MS_marksystemobject sp_copysnapshot
  952. go
  953. grant execute on dbo.sp_copysnapshot to public
  954. go
  955.  
  956. if exists (select * from sysobjects
  957.      where type = 'P '
  958.             and name = 'sp_copysubscription')
  959.      drop procedure sp_copysubscription
  960. go
  961.  
  962. print ''
  963. print 'Creating procedure sp_copysubscription'
  964. go
  965. CREATE PROCEDURE sp_copysubscription (
  966. @filename nvarchar(260),
  967. @temp_dir nvarchar(260) = NULL,
  968. -- Directory contains temp files. If not specified, SQL
  969. -- server default data directory will be used.
  970. @overwrite_existing_file bit = 0
  971. )
  972. AS
  973.  
  974.     SET NOCOUNT ON
  975.  
  976.     /*
  977.     ** Declarations.
  978.     */
  979.     declare @cmd nvarchar(4000)
  980.     declare @retcode int
  981.     declare @data_path nvarchar(260)
  982.     declare @subscriber_srvid     int
  983.     declare @subscriber_db        sysname
  984.     declare @backup_path nvarchar(260)
  985.     declare @temp_data_path nvarchar(260)
  986.     declare @temp_log_path nvarchar(260)
  987.     declare @retention            int
  988.     declare @retention_date       datetime
  989.     declare @pubid                 uniqueidentifier
  990.  
  991.  
  992.     /*
  993.     * Initializations
  994.     */
  995.     select @retcode = 0
  996.     select @subscriber_srvid = 0
  997.     select @subscriber_db = db_name()
  998.  
  999.     -- We only support single file attach. Check to make sure
  1000.     -- there are only 2 files, one data file and one log file
  1001.     if (select count(*) from sysfiles) > 2
  1002.     begin
  1003.         raiserror(21212,16, -1)
  1004.         return 1
  1005.     end
  1006.  
  1007.     /* Make sure all tran sub allows attach */
  1008.     declare @publication                 sysname
  1009.     declare @publisher                    sysname
  1010.     declare @tran_found                    bit
  1011.     declare @merge_found                bit
  1012.     select @tran_found = 0
  1013.     select @merge_found = 0
  1014.  
  1015.     /* 
  1016.     ** Make sure all merge subscriptions in the current database 
  1017.     ** have allow_subscription_copy set to TRUE
  1018.     ** and there are no push subscriptions. 
  1019.     */
  1020.     if exists (select * from sysobjects where name = 'MSsubscription_agents')
  1021.     begin
  1022.         set @publisher = NULL
  1023.         -- Not using @publication because share agent case.
  1024.         select top 1 @publisher = publisher from MSsubscription_agents where
  1025.             allow_subscription_copy = 0
  1026.         IF @publisher is not null
  1027.         BEGIN
  1028.             RAISERROR(21236, 16, -1, @publisher)
  1029.             RETURN (1)
  1030.         END
  1031.  
  1032.         set @publisher = null
  1033.         select top 1 @publisher = publisher from MSreplication_subscriptions where
  1034.             subscription_type = 0
  1035.         IF @publisher is not null
  1036.         BEGIN
  1037.             RAISERROR(21237, 16, -1, @publisher)            
  1038.             RETURN (1)
  1039.         END
  1040.         if exists (select * from MSsubscription_agents)
  1041.             select @tran_found = 1
  1042.     end            
  1043.  
  1044.     /* 
  1045.     ** Make sure all merge subscriptions in the current database 
  1046.     ** have allow_subscription_copy set to TRUE
  1047.     ** and there are no push subscriptions. 
  1048.     */
  1049.     if exists (select * from sysobjects where name = 'sysmergepublications')
  1050.         begin
  1051.             set @publication = NULL
  1052.             select top 1 @publication = name from sysmergepublications where
  1053.                 allow_subscription_copy = 0
  1054.             IF @publication is not null
  1055.                 BEGIN
  1056.                     RAISERROR (21204, 16, -1, @publication)    
  1057.                     RETURN (1)
  1058.                 END
  1059.  
  1060.             set @publication = null
  1061.             select top 1 @publication = p.name from sysmergepublications p, 
  1062.                 sysmergesubscriptions s where
  1063.                 p.pubid = s.pubid and
  1064.                 s.subid <> s.pubid and 
  1065.                 db_name = db_name() collate database_default and 
  1066.                 subscriber_server = convert(nvarchar(4000), SERVERPROPERTY('ServerName')) collate database_default  and
  1067.                 s.subscription_type = 0
  1068.             IF @publication is not null
  1069.             BEGIN
  1070.                 RAISERROR(21238, 16, -1, @publication)            
  1071.                 RETURN (1)
  1072.             END
  1073.  
  1074.             -- Does db contains subscriptions?
  1075.             if exists (select * from sysmergesubscriptions where subid <> pubid and 
  1076.                 db_name = db_name() collate database_default and 
  1077.                 subscriber_server = convert(nvarchar(4000), SERVERPROPERTY('ServerName')) collate database_default)
  1078.                 select @merge_found = 1
  1079.  
  1080.             /* Retention check : Make sure that the subscription copy is not too old */
  1081.             declare PC CURSOR LOCAL FAST_FORWARD for select DISTINCT p.name, p.pubid, p.retention from sysmergepublications p, sysmergesubscriptions s 
  1082.                 where s.subid=p.pubid and s.pubid=p.pubid for read only
  1083.             open PC
  1084.             fetch PC into @publication, @pubid, @retention 
  1085.             
  1086.             WHILE (@@fetch_status <> -1)
  1087.                 BEGIN
  1088.                     /* Compute the retention period cutoff dates per publication */
  1089.                     select @retention_date = dateadd(day, -@retention, getdate())
  1090.                        if @retention is not NULL and @retention > 0
  1091.                     begin
  1092.                         if not exists (select coldate from sysmergearticles , MSmerge_genhistory 
  1093.                                             where    nickname = art_nick 
  1094.                                                     and coldate > @retention_date 
  1095.                                                     and sysmergearticles.pubid = @pubid)
  1096.                             begin
  1097.                                 RAISERROR (21306, 16, -1, @publication)
  1098.                                 return (1)
  1099.                             end                                
  1100.                     end
  1101.                     fetch PC into @publication, @pubid, @retention
  1102.                 END
  1103.  
  1104.         end            
  1105.  
  1106.     if @tran_found = 0 and @merge_found = 0
  1107.     begin
  1108.         raiserror(21239, 16 , -1)
  1109.         return (1)
  1110.     end
  1111.     
  1112.     -- Security check
  1113.     -- Only DBO or sysadmin can do this
  1114.     -- The user also must have create db permissions.
  1115.     exec @retcode = dbo.sp_MSreplcheck_subscribe
  1116.     IF @retcode <> 0 or @@error <> 0
  1117.         return 1
  1118.  
  1119.     if @overwrite_existing_file is null
  1120.         set @overwrite_existing_file = 0
  1121.  
  1122.     -- Check to see if the file already exists
  1123.     declare @exists bit
  1124.  
  1125.     if @overwrite_existing_file = 0
  1126.     begin
  1127.         exec @retcode = dbo.sp_MSget_file_existence @filename, @exists output
  1128.         if @@error <> 0 or @retcode <> 0
  1129.             return 1
  1130.         if @exists <> 0 
  1131.         begin
  1132.             raiserror(21214, 16, -1, @filename)
  1133.             return 1
  1134.         end
  1135.     end
  1136.  
  1137.     -- Check to see if have write permissions to the file location.
  1138.     -- Try create the file
  1139.     -- Echo text can be anything.
  1140.     select @cmd = 'echo Subscription copy failed. > "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '"'
  1141.     exec @retcode = master.dbo.xp_cmdshell @cmd, NO_OUTPUT
  1142.     if @@error <> 0 or @retcode <> 0
  1143.     begin
  1144.         raiserror(21247, 16, -1, @filename)
  1145.         select @retcode = 1
  1146.         goto Cleanup
  1147.     end    
  1148.     -- File should be created.
  1149.     exec @retcode = dbo.sp_MSget_file_existence @filename, @exists output
  1150.     if @@error <> 0 or @retcode <> 0
  1151.     begin
  1152.         select @retcode = 1
  1153.         goto Cleanup
  1154.     end
  1155.     if @exists = 0
  1156.     begin
  1157.         raiserror(21247,16, -1, @filename)
  1158.         select @retcode = 1
  1159.         goto Cleanup
  1160.     end
  1161.  
  1162.     /*
  1163.     ** Get the MSSQL DATA path. Note that users can have a SQLDataRoot directory different from SQLPath
  1164.     */
  1165.     if @temp_dir is null
  1166.     begin
  1167.         exec @retcode = master.dbo.sp_MSget_setup_paths
  1168.             @data_path = @temp_dir output
  1169.         IF @retcode <> 0 or @@error <> 0
  1170.             return 1
  1171.         select @temp_dir = @temp_dir + '\DATA\'
  1172.     end
  1173.     else
  1174.     begin
  1175.         -- Check to make sure working dir is valid.
  1176.         exec @retcode = dbo.sp_MSget_file_existence @temp_dir, @exists output
  1177.         if @@error <> 0 or @retcode <> 0
  1178.         begin
  1179.             select @retcode = 1
  1180.             goto Cleanup
  1181.         end
  1182.         if @exists = 0
  1183.         begin
  1184.             raiserror (21037, 16, -1, @temp_dir)        
  1185.             select @retcode = 1
  1186.             goto Cleanup
  1187.         end
  1188.         if substring(@temp_dir, len(@temp_dir), 1) <> '\'
  1189.             select @temp_dir = @temp_dir + '\'
  1190.     end
  1191.  
  1192.     -- Get temp db name
  1193.     -- Use a guid to avoid name colision.
  1194.     declare @dbname sysname
  1195.     select @dbname = db_name()
  1196.     declare @temp_db_name sysname
  1197.     declare @guid_name nvarchar(36)
  1198.     select @guid_name =  convert (nvarchar(36), newid())
  1199.  
  1200.     select @temp_db_name = 'repl_sub_restore_' + @guid_name
  1201.  
  1202.     select @backup_path = @temp_dir + @temp_db_name + '.bak'
  1203.  
  1204.     -- Create table used to signal attach or restored process to do different things
  1205.     if not exists (select * from sysobjects where name = 'MSreplication_restore_stage')
  1206.     begin 
  1207.         CREATE TABLE dbo.MSreplication_restore_stage
  1208.         (
  1209.         stage_id int -- not used for now
  1210.         )
  1211.         IF @@ERROR <> 0
  1212.             return 1
  1213.     end
  1214.     
  1215.     -- First backup the database to the file given
  1216.     -- Overwrite the existing file with INIT option.
  1217.     BACKUP DATABASE @dbname TO DISK = @backup_path WITH INIT
  1218.     if @@error<> 0
  1219.     begin
  1220.         select @retcode = 1
  1221.         goto Cleanup
  1222.     end
  1223.  
  1224.  
  1225.     -- Restore it to a temporary working database
  1226.     -- Get phy data and log file name for the temp db
  1227.     select @temp_data_path = @temp_dir + @temp_db_name + '.mdf'
  1228.     select @temp_log_path = @temp_dir + @temp_db_name + '.ldf'
  1229.  
  1230.     -- Get the command
  1231.     select @cmd = 'restore database ' + quotename(@temp_db_name) + ' from disk = ' 
  1232.         + quotename(@backup_path,'''') + ' with replace, move '
  1233.  
  1234.     -- Get the logical file name for data file.
  1235.     select @cmd = @cmd + quotename(rtrim(name),'''') from sysfiles where
  1236.         (status & 0x40) = 0
  1237.  
  1238.     -- Use passed in filename as phy data file name for the temp db
  1239.  
  1240.     -- Use the passed in file as phy data file for the temp db
  1241.     select @cmd = @cmd + ' to ' + quotename(@temp_data_path,'''') + ', move '
  1242.  
  1243.     -- Get the logical file name for the log file
  1244.     select @cmd = @cmd + quotename(rtrim(name),'''') from sysfiles where
  1245.         (status & 0x40) <> 0
  1246.  
  1247.     -- Use the passed in file as phy file for the temp db
  1248.     select @cmd = @cmd + ' to ' + quotename(@temp_log_path,'''') + ' '
  1249.     exec (@cmd)
  1250.     if @@error<> 0
  1251.     begin
  1252.         select @retcode = 1
  1253.         goto Cleanup
  1254.     end
  1255.  
  1256.     -- Once we successfully restored, we delete to back up file to save disk space.
  1257.     if @backup_path is not null
  1258.     begin
  1259.         select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@backup_path) collate database_default + '"' 
  1260.         EXEC master..xp_cmdshell @cmd, NO_OUTPUT
  1261.         set @backup_path = null
  1262.     end
  1263.  
  1264.     -- Prepare the database for detach. 2 things will be done
  1265.     -- 1. Set a flag to indicate that this is a prepare sub db for detach
  1266.     -- 2. For merge, create table to store sysservers info for later fixing up after attach
  1267.     select @cmd = quotename(@temp_db_name) + '.dbo.sp_MSprepare_sub_for_detach'
  1268.     
  1269.     exec @retcode = @cmd @subscriber_srvid = @subscriber_srvid, @subscriber_db = @subscriber_db
  1270.     if @retcode<>0 or @@error<>0
  1271.     begin
  1272.         select @retcode = 1
  1273.         goto Cleanup
  1274.     end
  1275.  
  1276.     -- Shink the size of the temp db before detach
  1277.     DBCC SHRINKDATABASE (@temp_db_name, 10)
  1278.     if @@error <> 0
  1279.         goto Cleanup
  1280.  
  1281.     -- detach the database
  1282.     -- Wait for the db to be closed
  1283.     WAITFOR DELAY '00:00:00.500'
  1284.     exec @retcode = sp_detach_db @temp_db_name
  1285.     if @retcode<>0 or @@error<>0
  1286.     begin
  1287.         select @retcode = 1
  1288.         goto Cleanup
  1289.     end
  1290.  
  1291.     -- Delete the log file to save disk space
  1292.     if @temp_log_path is not null
  1293.     begin
  1294.         select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_log_path) collate database_default + '"' 
  1295.         EXEC master..xp_cmdshell @cmd, NO_OUTPUT
  1296.         set @temp_log_path = null
  1297.     end
  1298.  
  1299.     -- Compress the file
  1300.     exec @retcode = master..xp_makecab
  1301.         @cabfilename = @filename,
  1302.         @compression_mode ='mszip',
  1303.         @verbose_level = 0,
  1304.         @filename1 = @temp_data_path
  1305.     if @retcode<>0 or @@error<>0
  1306.     begin
  1307.         select @retcode = 1
  1308.         goto Cleanup
  1309.     end
  1310.  
  1311.  
  1312. Cleanup:
  1313.     if exists (select * from sysobjects where name = 'MSreplication_restore_stage')
  1314.         drop table dbo.MSreplication_restore_stage
  1315.  
  1316.  
  1317.     if exists (select * from master..sysdatabases where name = @temp_db_name collate database_default)
  1318.     begin
  1319.         select @cmd = 'drop database ' + quotename(@temp_db_name)
  1320.         exec (@cmd)
  1321.     end
  1322.  
  1323.     if @backup_path is not null
  1324.     begin
  1325.         select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@backup_path) collate database_default + '"' 
  1326.         EXEC master..xp_cmdshell @cmd, NO_OUTPUT
  1327.     end
  1328.  
  1329.     if @temp_data_path is not null
  1330.     begin
  1331.         select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_data_path) collate database_default + '"' 
  1332.         EXEC master..xp_cmdshell @cmd, NO_OUTPUT
  1333.     end
  1334.  
  1335.     if @temp_log_path is not null
  1336.     begin
  1337.         select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_log_path) collate database_default + '"' 
  1338.         EXEC master..xp_cmdshell @cmd, NO_OUTPUT
  1339.     end
  1340.  
  1341.     if @retcode <> 0
  1342.     begin
  1343.         select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '"' 
  1344.         EXEC master..xp_cmdshell @cmd, NO_OUTPUT
  1345.     end
  1346.  
  1347.     return @retcode
  1348. go
  1349. EXEC dbo.sp_MS_marksystemobject sp_copysubscription
  1350. GO
  1351. grant execute on dbo.sp_copysubscription to public
  1352.  
  1353. if exists (select * from sysobjects
  1354.      where type = 'P '
  1355.             and name = 'sp_attachsubscription')
  1356.      drop procedure sp_attachsubscription
  1357. go
  1358.  
  1359. print ''
  1360. print 'Creating procedure sp_attachsubscription'
  1361. go
  1362. CREATE PROCEDURE sp_attachsubscription (
  1363. @dbname    sysname,
  1364. @filename nvarchar(260),
  1365. @subscriber_security_mode        int = NULL,                        /* 0 standard; 1 integrated */
  1366. @subscriber_login                sysname = NULL,
  1367. @subscriber_password            sysname = NULL
  1368. )
  1369. AS
  1370.  
  1371.     SET NOCOUNT ON
  1372.  
  1373.     /*
  1374.     ** Declarations.
  1375.     */
  1376.     declare @cmd nvarchar(4000)
  1377.     declare @retcode int
  1378.     DECLARE @platform_nt binary
  1379.     declare @copy_created bit
  1380.     declare @exists bit
  1381.  
  1382.     select @platform_nt = 0x1    
  1383.     select @retcode = 0
  1384.     select @copy_created = 0
  1385.     select @exists = 0
  1386.  
  1387.     -- Parameter check: @subscriber_security_mode
  1388.     if @subscriber_security_mode is null
  1389.     begin
  1390.         if ( platform() & @platform_nt ) = @platform_nt
  1391.             select @subscriber_security_mode = 1
  1392.         else
  1393.             select @subscriber_security_mode = 0
  1394.     end    
  1395.  
  1396.     if ( ( platform() & @platform_nt ) <> @platform_nt and @subscriber_security_mode = 1 )
  1397.     begin
  1398.         RAISERROR(21038, 16, -1)
  1399.         RETURN (1)
  1400.     end
  1401.  
  1402.     if (@subscriber_security_mode = 0) and (@subscriber_login IS NULL or rtrim(@subscriber_login) = '')
  1403.         set @subscriber_login = 'sa'
  1404.  
  1405.     -- Check to make sure the database does not exists.
  1406.     if exists (select * from master..sysdatabases where name = @dbname collate database_default)
  1407.     begin
  1408.         raiserror(20621, 16, -1, @dbname)
  1409.         return (1)
  1410.     end
  1411.  
  1412.     -- Check to see if users has permissions to create database
  1413.     -- permissions() have to be run in master to return create db permission.
  1414.     declare @pm int
  1415.     exec @retcode = master.dbo.sp_executesql N'select @pm = permissions()', N'@pm int output', @pm output
  1416.     if @@error <> 0 or @retcode <> 0
  1417.         return 1
  1418.     if @pm & 1 = 0
  1419.     begin
  1420.         raiserror(20618, 16, -1)
  1421.         return 1
  1422.     end
  1423.  
  1424.     -- Decompress the file
  1425.     -- We have to copy the file to another location first. 
  1426.     -- (cannot use source as destination')
  1427.     declare @temp_copy nvarchar(260)
  1428.     declare @file_dir nvarchar(260)
  1429.     declare @file_name nvarchar(260)
  1430.     declare @dir_cmd nvarchar(260)
  1431.     -- Set @drive_cmd if needed 
  1432.     -- Set temp copy to be the file directory first
  1433.     -- Note @file_dir include '\'
  1434.     if (charindex('\', @filename, 1) = 0)
  1435.     begin
  1436.         select @file_dir = ''
  1437.         select @file_name = @filename
  1438.     end
  1439.     else
  1440.     begin
  1441.         select @file_dir = left(@filename,len(@filename) + 1 - 
  1442.             charindex('\', reverse(@filename), 1))
  1443.         select @file_name = right(@filename, len(@filename) - len(@file_dir))
  1444.     end
  1445.     -- Get guid name
  1446.     declare @guid_name nvarchar(36)
  1447.     select @guid_name =  convert (nvarchar(36), newid())
  1448.     select @temp_copy = @file_dir + @guid_name + '.tmp'
  1449.  
  1450.  
  1451.     -- copy file
  1452.     select @cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '" "' + fn_escapecmdshellsymbolsremovequotes(@temp_copy) collate database_default + '"'
  1453.     exec @retcode = master.dbo.xp_cmdshell @cmd, NO_OUTPUT
  1454.     if @@error <> 0 or @retcode <> 0
  1455.     begin
  1456.         raiserror(21248, 16, -1, @filename)
  1457.         select @retcode = 1
  1458.         goto Cleanup
  1459.     end    
  1460.  
  1461.     exec @retcode = dbo.sp_MSget_file_existence @temp_copy, @exists output
  1462.     if @@error <> 0 or @retcode <> 0
  1463.     begin
  1464.         select @retcode = 1
  1465.         goto Cleanup
  1466.     end
  1467.     if @exists = 0
  1468.     begin
  1469.         raiserror(21247, 16, -1, @temp_copy)        
  1470.         select @retcode = 1
  1471.         goto Cleanup
  1472.     end
  1473.  
  1474.     select @copy_created = 1
  1475.  
  1476.     -- decompress
  1477.     exec @retcode = master.dbo.xp_unpackcab 
  1478.         @cabfilename = @temp_copy,
  1479.         @destination_folder = @file_dir,
  1480.         @verbose_level = 0,
  1481.         @destination_file = @file_name,
  1482.         @suppress_messages = 1
  1483.         
  1484.     if @@error <> 0 
  1485.     begin
  1486.         select @retcode = 1
  1487.         goto Cleanup
  1488.     end
  1489.  
  1490.     if @retcode in (1030,1029,2005)
  1491.     begin
  1492.         raiserror(20609, 16, -1, @filename)
  1493.         select @retcode = 1
  1494.         goto Cleanup
  1495.     end    
  1496.     else if @retcode <> 0
  1497.     -- re-issue the command to get errors
  1498.     begin
  1499.         exec @retcode = master.dbo.xp_unpackcab 
  1500.             @cabfilename = @temp_copy,
  1501.             @destination_folder = @file_dir,
  1502.             @verbose_level = 0,
  1503.             @destination_file = @file_name,
  1504.             @suppress_messages = 0
  1505.         select @retcode = 1
  1506.         goto Cleanup
  1507.     end
  1508.  
  1509.     -- Attach
  1510.     exec @retcode = dbo.sp_attach_single_file_db
  1511.         @dbname = @dbname,
  1512.         @physname = @filename
  1513.     if @retcode<>0 or @@error<>0
  1514.     begin
  1515.         raiserror(21248, 16, -1, @filename)
  1516.         select @retcode = 1
  1517.         goto Cleanup
  1518.     end
  1519.  
  1520.  
  1521.     -- Prepare the database for detach. 2 things will be done
  1522.     -- 1. Set a flag to indicate that this is a prepare sub db for detach
  1523.     -- 2. For merge, create table to store sysservers info for later fixing up after attach
  1524.     select @cmd = quotename(@dbname) + '.dbo.sp_MSrestore_sub'
  1525.     exec @retcode = @cmd
  1526.         @subscriber_security_mode = @subscriber_security_mode,    
  1527.         @subscriber_login = @subscriber_login,
  1528.         @subscriber_password = @subscriber_password
  1529.     if @retcode<>0 or @@error<>0
  1530.     begin
  1531.         select @retcode = 1
  1532.         goto Cleanup
  1533.     end
  1534.  
  1535. Cleanup:
  1536.     if @retcode <> 0
  1537.     begin
  1538.         -- The files will be deleted if some thing failed. 
  1539.         if exists (select * from master..sysdatabases where name = @dbname collate database_default)
  1540.             begin
  1541.                 select @cmd = 'drop database ' + quotename(@dbname)
  1542.                 exec (@cmd)
  1543.             end                
  1544.     end
  1545.  
  1546.     if @temp_copy is not null
  1547.     begin
  1548.         -- Restore the original file, ignore errors
  1549.         if @retcode <> 0 and @copy_created = 1
  1550.         begin
  1551.             select @cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@temp_copy) collate database_default + '" "' + fn_escapecmdshellsymbolsremovequotes(@filename) collate database_default + '"'
  1552.             exec master.dbo.xp_cmdshell @cmd, NO_OUTPUT
  1553.         end
  1554.  
  1555.         -- Delete the temp file.
  1556.         select @cmd = 'del "' + fn_escapecmdshellsymbolsremovequotes(@temp_copy) collate database_default+ '"' 
  1557.         EXEC master..xp_cmdshell @cmd, NO_OUTPUT
  1558.     end
  1559.  
  1560.     return @retcode
  1561. go
  1562. EXEC dbo.sp_MS_marksystemobject sp_attachsubscription
  1563. grant execute on dbo.sp_attachsubscription to public
  1564. GO
  1565.  
  1566. --------------------------------------------------------------------------------
  1567. --.    System objects (replcom.sql)
  1568. --------------------------------------------------------------------------------
  1569. if exists (select * from sysobjects
  1570.     where type = 'P'
  1571.       and name = 'sp_adddistributiondb')
  1572.      drop procedure sp_adddistributiondb
  1573.  
  1574. GO
  1575. raiserror('Creating procedure sp_adddistributiondb', 0,1)
  1576. go
  1577.  
  1578. CREATE PROCEDURE sp_adddistributiondb (
  1579.     @database sysname,
  1580.     @data_folder nvarchar(255) = NULL,
  1581.     @data_file nvarchar(255) = NULL,            /* physical file name */
  1582.     @data_file_size int = 2,                    /* Default: 2MB */            
  1583.     @log_folder nvarchar(255) = NULL,
  1584.     @log_file nvarchar(255) = NULL,             /* physical file name */
  1585.     @log_file_size int = 0,
  1586.     @min_distretention int = 0,                 /* min distribution retention period in hours */
  1587.     @max_distretention int = 72,                /* max distribution retention period in hours */
  1588.     @history_retention int = 48,                /* history retention period in hours */
  1589.     @security_mode int = 0,                     /* distributor login security 0 standard 1 integrated */
  1590.     @login sysname = 'sa',                      /* standard login name */
  1591.     @password sysname = NULL,                   /* standard login password */
  1592.     @createmode int = 0,  /* 0: use create db for attach (recommended), 
  1593.                             1: create db or use existing but no attach (this is the old way), 
  1594.                             2: create for instdist and detach only */
  1595.     @from_scripting bit = 0
  1596.     ) AS
  1597.  
  1598.     SET NOCOUNT ON
  1599.  
  1600.     /*
  1601.     ** Declarations.
  1602.     */
  1603.     DECLARE @data_path nvarchar(512)
  1604.     DECLARE @log_path nvarchar(512)
  1605.     
  1606.     DECLARE @data_path_quoted_for_copy nvarchar(512)
  1607.     DECLARE @log_path_quoted_for_copy nvarchar(512)
  1608.  
  1609.     DECLARE @logical_data_file nvarchar(255)
  1610.     DECLARE @logical_log_file nvarchar(255)
  1611.     DECLARE @canneddbdata_file nvarchar(255)
  1612.     DECLARE @canneddblog_file nvarchar(255)
  1613.     DECLARE @filecopy_cmd nvarchar(255)
  1614.     DECLARE @file_exists bit
  1615.     DECLARE @data_file_preexists int
  1616.     DECLARE @log_file_preexists int
  1617.     DECLARE @osql_path nvarchar(260)
  1618.     DECLARE @osql_cmd nvarchar(1000)
  1619.     DECLARE @osql_for_nt int
  1620.     DECLARE @devnum int
  1621.     --DECLARE @num_pages int
  1622.     DECLARE @retcode int
  1623.     DECLARE @reg_key nvarchar(255)
  1624.     DECLARE @agentname nvarchar(100)
  1625.     DECLARE @command nvarchar (2048)
  1626.     DECLARE @distbit int
  1627.     DECLARE @install_path nvarchar(255)
  1628.     DECLARE @mssql_data_path nvarchar(255)
  1629.     DECLARE @on_clause nvarchar(512)
  1630.     DECLARE @logon_clause nvarchar(512)
  1631.     DECLARE @distproc nvarchar(255)
  1632.     DECLARE @major_version int
  1633.     DECLARE @db_exists bit
  1634.     DECLARE @trunc_log_bit int
  1635.     DECLARE @description nvarchar(100)
  1636.     DECLARE @category_name sysname
  1637.     DECLARE @createmode_attach int
  1638.     DECLARE @createmode_noattach int
  1639.     DECLARE @createmode_fordetach int
  1640.  
  1641.     --DECLARE @filegrowth nvarchar(10)
  1642.     DECLARE @data_file_size_str nvarchar(10)
  1643.     DECLARE @log_file_size_str nvarchar(10)
  1644.     DECLARE @platform_nt binary
  1645.  
  1646.     --DECLARE @max_datafile_size int
  1647.     --DECLARE @max_logfile_size int
  1648.     
  1649.     IF @password = N''
  1650.         select @password = NULL
  1651.  
  1652.     select @platform_nt = 0x1
  1653.     --select @filegrowth = N'512KB'
  1654.  
  1655.     -- on error, delete the data and log files only if they didn't pre-exist.
  1656.     -- by default, assume they pre-exist.
  1657.     select @data_file_preexists = 1
  1658.     select @log_file_preexists = 1
  1659.     select @file_exists = 0
  1660.  
  1661.     if (@data_file_size IS NULL) or (@data_file_size = 0)
  1662.         select @data_file_size_str = N'512KB'
  1663.     else
  1664.         select @data_file_size_str = convert(nvarchar(10), @data_file_size)
  1665.  
  1666.     if (@log_file_size IS NULL) or (@log_file_size = 0)
  1667.         select @log_file_size_str = N'512KB'
  1668.     else
  1669.         select @log_file_size_str = convert(nvarchar(10), @log_file_size)
  1670.     
  1671.     --if (@data_file_size > 16)
  1672.     --  select @max_datafile_size = @data_file_size
  1673.     --else
  1674.     --  select @max_datafile_size = 16
  1675.     
  1676.     --if (@log_file_size > 16)
  1677.     --  select @max_logfile_size = @log_file_size
  1678.     --else
  1679.     --  select @max_logfile_size = 16
  1680.  
  1681.     select @createmode_attach = 0, @createmode_noattach = 1, @createmode_fordetach = 2
  1682.     SELECT @trunc_log_bit = 8
  1683.     SELECT @distbit = 16
  1684.  
  1685.     if (@createmode <> @createmode_fordetach)
  1686.     begin
  1687.     
  1688.         /* 
  1689.         ** Check if replication components are installed on this server
  1690.         */
  1691.         exec @retcode = dbo.sp_MS_replication_installed
  1692.         if (@retcode <> 1)
  1693.         begin
  1694.             return (1)
  1695.         end
  1696.     
  1697.         /* 
  1698.         ** Check for invalid security modes
  1699.         */
  1700.         IF @security_mode < 0 OR @security_mode > 1
  1701.         BEGIN
  1702.             RAISERROR(14109, 16, -1)
  1703.             RETURN (1)
  1704.         END
  1705.  
  1706.         IF ( ( @platform_nt != platform() & @platform_nt ) and @security_mode = 1)
  1707.         BEGIN
  1708.             RAISERROR(21038, 16, -1)
  1709.             RETURN (1)
  1710.         END
  1711.     
  1712.         /* 
  1713.         ** Check for invalid retention values 
  1714.         */
  1715.         IF @min_distretention < 0 OR @max_distretention < 0 
  1716.         BEGIN
  1717.             RAISERROR(14106, 16, -1)
  1718.             RETURN (1)
  1719.         END
  1720.         IF @min_distretention > @max_distretention
  1721.         BEGIN
  1722.             RAISERROR(14107, 16, -1) 
  1723.             RETURN (1)
  1724.         END
  1725.  
  1726.         /*
  1727.         ** Check to make sure this is a distributor
  1728.         */
  1729.         IF NOT EXISTS (SELECT * FROM master..sysservers
  1730.               WHERE UPPER(datasource) = UPPER(@@SERVERNAME) collate database_default
  1731.                  AND srvstatus & 8 <> 0)
  1732.         BEGIN
  1733.             RAISERROR (14114, 16, -1, @@SERVERNAME)
  1734.             RETURN(1)
  1735.         END
  1736.     
  1737.         /*
  1738.         ** Check if database is already configured as a distributor database
  1739.         */
  1740.         IF EXISTS (SELECT * FROM msdb..MSdistributiondbs WHERE name = @database collate database_default)
  1741.         BEGIN
  1742.             RAISERROR (14119, 16, -1, @database)
  1743.             RETURN(1)
  1744.         END    
  1745.     end
  1746.  
  1747.     /* 
  1748.     ** Get path to osql client (TOOLS) directory
  1749.     */
  1750.     EXECUTE @retcode = master.dbo.sp_MSgettools_path @osql_path OUTPUT
  1751.     IF ( @retcode <> 0 ) or ( @@ERROR <> 0 ) or ( @osql_path is NULL ) or ( @osql_path = '' )
  1752.     BEGIN
  1753.         GOTO UNDO       
  1754.     END
  1755.  
  1756.     /* 
  1757.     ** Get path to version specific INSTALL directory
  1758.     */
  1759.     exec @retcode = master.dbo.sp_MSget_setup_paths
  1760.         @sql_path = @install_path output,
  1761.         @data_path = @mssql_data_path output
  1762.     IF @retcode <> 0 or @install_path is NULL or @install_path='' or @mssql_data_path = ''
  1763.     BEGIN
  1764.         GOTO UNDO       
  1765.     END
  1766.  
  1767.     IF @data_folder IS NULL or @data_folder = ''
  1768.         select @data_folder = @mssql_data_path + '\DATA'
  1769.  
  1770.     IF @log_folder IS NULL or @log_folder = ''
  1771.         select @log_folder = @mssql_data_path + '\DATA'
  1772.  
  1773.     IF @data_file IS NULL
  1774.         SELECT @data_file = @database + '.MDF'
  1775.  
  1776.     IF @log_file IS NULL
  1777.         SELECT @log_file = @database + '.LDF'
  1778.  
  1779.     if substring(@data_folder, len(@data_folder), 1) = '\'
  1780.     select @data_folder = substring (@data_folder, 1, len(@data_folder) -1)
  1781.     if substring(@log_folder, len(@log_folder), 1) = '\'
  1782.     select @log_folder = substring (@log_folder, 1, len(@log_folder) -1)
  1783.  
  1784.     SELECT @data_path = @data_folder + '\' + @data_file
  1785.     SELECT @log_path = @log_folder + '\' + @log_file
  1786.  
  1787.     SELECT @data_path_quoted_for_copy = '"' + fn_escapecmdshellsymbolsremovequotes(@data_folder) collate database_default + '\' + fn_escapecmdshellsymbolsremovequotes(@data_file) collate database_default + '"'
  1788.     SELECT @log_path_quoted_for_copy = '"' + fn_escapecmdshellsymbolsremovequotes(@log_folder) collate database_default + '\' + fn_escapecmdshellsymbolsremovequotes(@log_file) collate database_default + '"'
  1789.  
  1790.     select @logical_data_file = @database
  1791.  
  1792.     /* 
  1793.     ** Truncate the logical log file name back to 128 characters
  1794.     ** long so the 'CREATE DATABASE' statement won't complain.
  1795.     */
  1796.     /* LEN(@logical_log_file) = LEN(@database) + LEN('_log') and
  1797.        LEN(@logical_log_file) <= 128 implies 
  1798.        LEN(@database) <=124 */
  1799.     IF (LEN(@database) > 124)
  1800.         SELECT @logical_log_file = SUBSTRING(@database, 1, 124) + '_log'  
  1801.     ELSE 
  1802.         SELECT @logical_log_file = @database + '_log'
  1803.  
  1804.     if (@createmode = @createmode_attach)
  1805.     begin
  1806.         select @canneddbdata_file = @mssql_data_path + '\DATA\DISTMDL.MDF'
  1807.         select @canneddblog_file = @mssql_data_path + '\DATA\DISTMDL.LDF'
  1808.  
  1809.         exec dbo.sp_MSget_file_existence @canneddbdata_file, @file_exists OUTPUT
  1810.         if (@file_exists = 0)
  1811.         begin
  1812.             /* Fallback to mode where instdist.sql needs to be run */
  1813.             select @createmode = @createmode_noattach
  1814.         end
  1815.  
  1816.         exec dbo.sp_MSget_file_existence @canneddblog_file, @file_exists OUTPUT
  1817.         if (@file_exists = 0)
  1818.         begin
  1819.             /* Fallback to mode where instdist.sql needs to be run */
  1820.             select @createmode = @createmode_noattach
  1821.         end
  1822.     end
  1823.  
  1824.     /*
  1825.     ** Create the distributor database if it does not exist
  1826.     */
  1827.     IF NOT EXISTS (SELECT * from master..sysdatabases WHERE name = @database collate database_default) AND (@createmode <> @createmode_attach)
  1828.     BEGIN
  1829.  
  1830.         -- Note: Use system's default file growth.
  1831.         IF @logical_data_file IS NOT NULL AND NOT EXISTS (SELECT * FROM master..sysdevices WHERE name = @logical_data_file collate database_default)
  1832.         BEGIN
  1833.             SELECT @on_clause = ' ON (NAME =''' + @logical_data_file + ''',FILENAME=''' + REPLACE( @data_path, '''', '''''' ) + 
  1834.                 ''', SIZE=' + @data_file_size_str + ', MAXSIZE = UNLIMITED)'
  1835.         END
  1836.  
  1837.         IF @logical_log_file IS NOT NULL AND NOT EXISTS (SELECT * FROM master..sysdevices WHERE name = @logical_log_file collate database_default)
  1838.         BEGIN
  1839.             SELECT @logon_clause = ' LOG ON (NAME =''' + @logical_log_file + ''',FILENAME=''' + REPLACE( @log_path, '''', '''''' ) + 
  1840.                 ''', SIZE=' + @log_file_size_str + ', MAXSIZE= UNLIMITED)'          
  1841.         END
  1842.  
  1843.         /*
  1844.         ** Create distributor database
  1845.         */
  1846.         SELECT @command = 'USE master  CREATE DATABASE ' +  QUOTENAME(@database) + 
  1847.             + isnull(@on_clause, ' ') + isnull(@logon_clause, ' ')
  1848.  
  1849.         EXEC (@command)
  1850.         IF @@ERROR <> 0
  1851.             RETURN (1)
  1852.         SELECT @db_exists = 0
  1853.     END
  1854.     ELSE IF NOT EXISTS (SELECT * from master..sysdatabases WHERE name = @database collate database_default) AND (@createmode = @createmode_attach)
  1855.     BEGIN
  1856.     /* DO THE CREATE DATABASE FOR ATTACH STUFF */
  1857.         
  1858.         exec dbo.sp_MSget_file_existence @data_path, @data_file_preexists OUTPUT
  1859.         if (@data_file_preexists = 1)
  1860.         begin
  1861.             raiserror(5170, 16, -1, @data_path)
  1862.             return 1
  1863.         end
  1864.     
  1865.         SELECT @on_clause = ' ON (NAME = ''' + @logical_data_file + ''', FILENAME=''' + REPLACE( @data_path, '''', '''''' ) + ''')'
  1866.         
  1867.         exec dbo.sp_MSget_file_existence @log_path, @log_file_preexists OUTPUT
  1868.         if (@log_file_preexists = 1)
  1869.         begin
  1870.             raiserror(5170, 16, -1, @log_path)
  1871.             return 1
  1872.         end
  1873.  
  1874.         SELECT @logon_clause = ' LOG ON (NAME = ''' + @logical_log_file + ''', FILENAME=''' + REPLACE( @log_path, '''', '''''' ) + ''')'
  1875.  
  1876.         select @filecopy_cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@canneddbdata_file) collate database_default + '" ' + @data_path_quoted_for_copy
  1877.         EXEC @retcode = master..xp_cmdshell @filecopy_cmd, NO_OUTPUT
  1878.         IF @retcode <> 0 OR @@ERROR <> 0
  1879.         BEGIN
  1880.             RAISERROR (14113, 16, -1, @filecopy_cmd, 'instdist.out')
  1881.             return (1)
  1882.         END
  1883.  
  1884.         select @filecopy_cmd = 'copy "' + fn_escapecmdshellsymbolsremovequotes(@canneddblog_file) collate database_default + '" ' + @log_path_quoted_for_copy
  1885.         EXEC @retcode = master..xp_cmdshell @filecopy_cmd, NO_OUTPUT
  1886.         IF @retcode <> 0 OR @@ERROR <> 0
  1887.         BEGIN
  1888.             RAISERROR (14113, 16, -1, @filecopy_cmd, 'instdist.out')
  1889.             return (1)
  1890.         END
  1891.  
  1892.         /*
  1893.         ** Create distributor database
  1894.         */
  1895.         SELECT @command = 'USE master  CREATE DATABASE ' +  QUOTENAME(@database) + 
  1896.             + @on_clause + @logon_clause + ' FOR ATTACH'
  1897.  
  1898.         EXEC (@command)
  1899.         IF @@ERROR <> 0
  1900.         begin
  1901.             RETURN (1)
  1902.         end
  1903.         dbcc dbreindexall(@database, 240) with no_infomsgs
  1904.  
  1905.         SELECT @db_exists = 0
  1906.     END
  1907.     ELSE
  1908.     BEGIN
  1909.         SELECT @db_exists = 1
  1910.     END
  1911.  
  1912.     -- Must make the dist db owned by sa so that the sps in it can select from
  1913.     -- security cache tables in tempdb by owership chain rule.
  1914.     declare @retcode2 int
  1915.     select @retcode2 = 0
  1916.     select @distproc = QUOTENAME(@database) + '.dbo.sp_executesql'
  1917.     SELECT @command = 
  1918.         -- If the db is created by sa or from attach, sa is dbo already.
  1919.         -- sp_changedbowner will fail is the new owner is an user in the db already.
  1920.         ' if not exists (select * from sysusers where sid = 0x01) ' +
  1921.         ' exec @retcode2 = dbo.sp_changedbowner ''sa'''
  1922.     EXEC @retcode = @distproc @command, N'@retcode2 int output', @retcode2 output
  1923.     IF @retcode <> 0 or @retcode2 <> 0 or @@ERROR <> 0
  1924.     BEGIN
  1925.         GOTO UNDO
  1926.     END
  1927.  
  1928.     /* Set the database option truncate log on checkpoint & turn off autoclose which is default of win9x*/
  1929.     IF EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE 
  1930.         name = @database collate database_default AND
  1931.         (status & @trunc_log_bit) = 0 )   -- if its not already marked
  1932.     BEGIN
  1933.         EXEC @retcode = dbo.sp_dboption @database, 'trunc. log on chkpt.', 'true'
  1934.         IF @retcode <> 0 OR @@ERROR <> 0
  1935.         BEGIN
  1936.             GOTO UNDO
  1937.         END
  1938.     END
  1939.  
  1940.     EXEC @retcode = dbo.sp_dboption @database, 'autoclose', 'false'
  1941.         IF @retcode <> 0 OR @@ERROR <> 0
  1942.         BEGIN
  1943.             GOTO UNDO
  1944.         END
  1945.  
  1946.     /*
  1947.     **
  1948.     ** Update sysdatabase category bit
  1949.     ** This is to prevent user from dropping the database.
  1950.     **/
  1951.     if (@createmode <> @createmode_fordetach)
  1952.     begin
  1953.         UPDATE master..sysdatabases SET category = category | @distbit WHERE name = @database collate database_default
  1954.         IF @@ERROR <> 0
  1955.         BEGIN
  1956.             GOTO UNDO
  1957.         END
  1958.     end
  1959.  
  1960.     /* 
  1961.     ** Install instdist.sql
  1962.     */
  1963.  
  1964.     if (@createmode <> @createmode_attach) OR (@db_exists = 1)
  1965.     begin
  1966.         if (( platform() & @platform_nt = @platform_nt ))
  1967.             select @osql_for_nt = 1
  1968.         else
  1969.             select @osql_for_nt = 0
  1970.  
  1971.         -- Always use integrated security on WINNT since @login passed-in is for remote 
  1972.         -- subscriber and may not have enough privilege to apply the script
  1973.         IF (@security_mode = 1 or @osql_for_nt = 1) AND NOT (@security_mode = 0 AND @createmode = 2)
  1974.         BEGIN
  1975.             SELECT @osql_cmd = '" "' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -E '  
  1976.             if serverproperty('instancename') is not null
  1977.                 SELECT @osql_cmd = @osql_cmd + ' -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
  1978.         END
  1979.         ELSE
  1980.         BEGIN
  1981.         -- cannot specify -S w/ -E for local execution, SID does not map 
  1982.         if (@osql_for_nt = 1)
  1983.             SELECT @osql_cmd = '" "' + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U"' + fn_escapecmdshellsymbols(@login) collate database_default + '" -P"' + 
  1984.                 fn_escapecmdshellsymbols(isnull(@password,'')) collate database_default + '" -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
  1985.         else
  1986.             SELECT @osql_cmd = '"'   + fn_escapecmdshellsymbolsremovequotes(@osql_path) collate database_default + '\binn\osql" -U"' + fn_escapecmdshellsymbols(@login) collate database_default + '" -P"' + 
  1987.                 fn_escapecmdshellsymbols(isnull(@password,'')) collate database_default + '" -S"' + fn_escapecmdshellsymbols(@@SERVERNAME) collate database_default + '" '
  1988.         END
  1989.     
  1990.         select @osql_cmd = @osql_cmd + '-l60 -t60 '
  1991.  
  1992.         -- We must use -b option to make osql return error code !!
  1993.         SELECT @osql_cmd = @osql_cmd + 
  1994.             ' -d"' + fn_escapecmdshellsymbols(@database) collate database_default + '" -b ' +
  1995.             ' -i' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.sql"' + 
  1996.             ' -o' + '"' + fn_escapecmdshellsymbolsremovequotes(@install_path) collate database_default + '\install\instdist.out"'
  1997.  
  1998.         if (@osql_for_nt = 1)
  1999.         BEGIN
  2000.             SELECT @osql_cmd = @osql_cmd + ' "'
  2001.         END
  2002.     
  2003.         EXEC @retcode = master..xp_cmdshell @osql_cmd
  2004.         IF @retcode <> 0 OR @@ERROR <> 0
  2005.         BEGIN
  2006.             RAISERROR (14113, 16, -1, @osql_cmd, 'instdist.out')
  2007.             GOTO UNDO       
  2008.         END
  2009.     end
  2010.     
  2011.     if (@createmode <> @createmode_fordetach)
  2012.     begin
  2013.         /* Set db_existed bit in MSrepl_version */
  2014.         IF @db_exists = 1
  2015.         BEGIN
  2016.             SELECT @distproc = 'UPDATE ' +
  2017.                 @database + '..MSrepl_version SET db_existed = 0x1'
  2018.     
  2019.             EXEC(@distproc)
  2020.             IF @@ERROR <> 0
  2021.             BEGIN
  2022.                 GOTO UNDO       
  2023.             END
  2024.         END
  2025.  
  2026.         DELETE msdb.dbo.MSdistributiondbs WHERE name = @database collate database_default
  2027.         IF @@ERROR <> 0
  2028.         BEGIN
  2029.             GOTO UNDO       
  2030.         END
  2031.  
  2032.         INSERT INTO msdb.dbo.MSdistributiondbs VALUES (
  2033.             @database, @min_distretention, @max_distretention, @history_retention
  2034.             )
  2035.         IF @@ERROR <> 0
  2036.         BEGIN
  2037.             GOTO UNDO       
  2038.         END
  2039.  
  2040.         -- This login need db_owner priviledge to call sps in distribution db
  2041.         declare @distributor_login sysname
  2042.         select @distributor_login = 'distributor_admin'
  2043.  
  2044.         select @command = quotename(@database) + '.dbo.sp_MSrepl_dbrole'
  2045.         exec @retcode = @command 'db_owner', @distributor_login, 'add'
  2046.         IF @@error <> 0 OR @retcode <> 0
  2047.             GOTO UNDO
  2048.  
  2049.         if @from_scripting = 0
  2050.         begin
  2051.             /*
  2052.             ** Create the history cleanup agent.
  2053.             */
  2054.             SELECT @agentname = formatmessage (20567, @database)
  2055.             SELECT @command =  'EXEC dbo.sp_MShistory_cleanup @history_retention = ' + 
  2056.                 CONVERT(nvarchar(12), @history_retention)
  2057.  
  2058.             IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and
  2059.                 UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
  2060.             BEGIN
  2061.                 EXEC @retcode = msdb.dbo.sp_delete_job 
  2062.                     @job_name = @agentname
  2063.                 IF @@ERROR <> 0 or @retcode <> 0
  2064.                 BEGIN
  2065.                     GOTO UNDO
  2066.                 END
  2067.             END
  2068.  
  2069.             set @description = formatmessage(20535)
  2070.  
  2071.             -- Get History Cleanup category name (assumes category_id = 12)
  2072.             select @category_name = name FROM msdb.dbo.syscategories where category_id = 12
  2073.  
  2074.             EXECUTE @retcode = dbo.sp_MSadd_repl_job @agentname,
  2075.             @subsystem = 'TSQL',
  2076.             @server = @@SERVERNAME,
  2077.             @databasename = @database,
  2078.             @description = @description,
  2079.             @freqtype = 4,    
  2080.             @freqsubtype = 4,         
  2081.             @freqsubinterval = 10,    /* Number of minutes between runs */ 
  2082.             @command = @command,
  2083.             @enabled = 1,
  2084.             @retryattempts = 0,
  2085.             @loghistcompletionlevel = 0,
  2086.             @category_name = @category_name
  2087.     
  2088.             IF @@ERROR <> 0 or @retcode <> 0
  2089.             BEGIN
  2090.                 GOTO UNDO
  2091.             END
  2092.  
  2093.             /*
  2094.             ** Create the distribution cleanup agent.
  2095.             */
  2096.             SELECT @agentname = formatmessage (20568, @database)
  2097.             SELECT @command =  'EXEC dbo.sp_MSdistribution_cleanup @min_distretention = ' + 
  2098.                 CONVERT(nvarchar(12), @min_distretention) + ', @max_distretention = ' +
  2099.                 CONVERT(nvarchar(12), @max_distretention)
  2100.  
  2101.             IF EXISTS (SELECT * FROM msdb..sysjobs_view WHERE name = @agentname collate database_default and
  2102.                 UPPER(originating_server) = UPPER(CONVERT(sysname, SERVERPROPERTY('ServerName'))))
  2103.             BEGIN
  2104.                 EXEC @retcode = msdb.dbo.sp_delete_job 
  2105.                     @job_name = @agentname
  2106.                 IF @@ERROR <> 0 or @retcode <> 0
  2107.                 BEGIN
  2108.                     GOTO UNDO
  2109.                 END
  2110.             END
  2111.  
  2112.             set @description = formatmessage(20541)
  2113.             -- Get Distribution Cleanup category name (assumes category_id = 11)
  2114.             select @category_name = name FROM msdb.dbo.syscategories where category_id = 11
  2115.     
  2116.             EXECUTE @retcode = msdb.dbo.sp_MSadd_repl_job @agentname,
  2117.             @subsystem = 'TSQL',
  2118.             @server = @@SERVERNAME,
  2119.             @databasename = @database,
  2120.             @description = @description,
  2121.             @freqtype = 4,    
  2122.             @freqsubtype = 4,         
  2123.             @freqsubinterval = 10,    /* Number of minutes between runs */ 
  2124.             @command = @command,
  2125.             @retryattempts = 0,
  2126.             @enabled = 0,
  2127.             @loghistcompletionlevel = 0,
  2128.             @category_name = @category_name,
  2129.             -- Start  and end time is 5 min off from the history cleanup, which use the default.
  2130.             @activestarttimeofday = 000500,
  2131.             @activeendtimeofday   = 000459
  2132.  
  2133.             IF @@ERROR <> 0 or @retcode <> 0
  2134.             BEGIN
  2135.                 GOTO UNDO
  2136.             end
  2137.         end
  2138.     end
  2139.     else
  2140.     begin
  2141.         /*detach */
  2142.         dbcc detachdb(@database)
  2143.     end
  2144.     
  2145.     RETURN(0)
  2146.  
  2147. UNDO:
  2148.  
  2149.     IF @db_exists = 0
  2150.         EXECUTE dbo.sp_dropdistributiondb @database
  2151.  
  2152.     /* Need to do it since sp_dropdistributiondb will fail in some cases */
  2153.     UPDATE master..sysdatabases SET category = category & ~@distbit WHERE name = @database collate database_default
  2154.     
  2155.     DELETE msdb.dbo.MSdistributiondbs where name = @database collate database_default
  2156.  
  2157.     /* drop the database and ignore error */
  2158.     IF @db_exists = 0 AND
  2159.         EXISTS (SELECT * from master..sysdatabases WHERE name = @database collate database_default)
  2160.     BEGIN
  2161.         SELECT @command = 'USE master  DROP DATABASE ' +  QUOTENAME(@database) 
  2162.         EXEC (@command)
  2163.     END
  2164.  
  2165.     if (@createmode = @createmode_attach)
  2166.     begin
  2167.         if (@data_file_preexists = 0)
  2168.         begin
  2169.             select @command = 'del ' + @data_path_quoted_for_copy
  2170.             exec master..xp_cmdshell @command
  2171.             --ignore errors
  2172.         end
  2173.         if (@log_file_preexists = 0)
  2174.         begin
  2175.             select @command = 'del ' + @log_path_quoted_for_copy
  2176.             exec master..xp_cmdshell @command
  2177.             --ignore errors
  2178.         end
  2179.     end
  2180.         
  2181.     RETURN(1)        
  2182. GO
  2183.  
  2184. if exists (select * from sysobjects
  2185.         where type = 'P'
  2186.             and name = 'sp_adddistpublisher')
  2187.     drop procedure sp_adddistpublisher
  2188.  
  2189. raiserror('Creating procedure sp_adddistpublisher', 0,1)
  2190. go
  2191.  
  2192. CREATE PROCEDURE sp_adddistpublisher (
  2193.     @publisher sysname,      /* publisher server name */
  2194.     @distribution_db sysname,
  2195.     @security_mode int = NULL,
  2196.     @login sysname = 'sa',
  2197.     @password sysname = NULL,
  2198.     @working_directory nvarchar(255),
  2199.     @trusted nvarchar(5) = NULL,
  2200.     @encrypted_password bit = 0,
  2201.     @thirdparty_flag bit = 0
  2202.         ) AS
  2203.  
  2204.     SET NOCOUNT ON
  2205.  
  2206.     /*
  2207.     ** Declarations.
  2208.     */
  2209.  
  2210.     DECLARE @retcode int
  2211.     DECLARE @reg_key nvarchar(255)
  2212.     DECLARE @distbit int
  2213.     DECLARE @active_value int
  2214.     DECLARE @server_added bit
  2215.     DECLARE @proc nvarchar(255)
  2216.     declare @fExists int
  2217.     declare @command nvarchar(255)
  2218.     declare @trusted_id bit
  2219.     declare @platform_nt binary
  2220.     declare @qv_replication varchar(10)
  2221.     declare @qv_replication_unlimited integer
  2222.     declare @qv_value_replication integer
  2223.     declare @enc_password nvarchar(524)
  2224.  
  2225.     select @platform_nt = 0x1
  2226.     select @qv_replication = '2745196162', @qv_replication_unlimited = 0
  2227.  
  2228.     SELECT @distbit = 16
  2229.     SELECT @server_added = 0
  2230.  
  2231.     /* 
  2232.     ** Check if replication components are installed on this server
  2233.     */
  2234.     exec @retcode = dbo.sp_MS_replication_installed
  2235.     if (@retcode <> 1)
  2236.     begin
  2237.         return (1)
  2238.     end
  2239.  
  2240.     IF @working_directory IS NULL or ltrim(rtrim(@working_directory)) = ''
  2241.     BEGIN
  2242.         RAISERROR (14043, 16, -1, '@working_directory')
  2243.         return (1)
  2244.     END
  2245.  
  2246.  
  2247.     /*
  2248.     ** Parameter Check:  @publisher.
  2249.     ** Check to make sure that the publisher is not NULL and that it
  2250.     ** conforms to the rules for identifiers.
  2251.     */
  2252.  
  2253.     IF @publisher IS NULL
  2254.         BEGIN
  2255.             RAISERROR (14043, 16, -1, '@publisher')
  2256.             return (1)
  2257.         END
  2258.  
  2259.     EXECUTE @retcode = dbo.sp_validname @publisher
  2260.  
  2261.     IF @@ERROR <> 0 OR @retcode <> 0
  2262.         return (1)
  2263.  
  2264.     IF @password = N''
  2265.         select @password = NULL
  2266.  
  2267.     /* On REPLICATION_LIMITED server, only local publisher is supported.
  2268.      * Note: The login and password registered for local publisher will be used for 
  2269.      * local agents to login to distributor, thus local publisher has to be installed first.
  2270.      * We choose not to support remote dist publshers on REPLICATION_LIMITED server altogether.
  2271.      * On NT, local agents will always use integrated security to log into 
  2272.      * distributor
  2273.      * Today, REPLICATION_LIMITED means desktop but we check specific sku entry just in case
  2274.     */
  2275.     exec @qv_value_replication = master.dbo.sp_MSinstance_qv @qv_replication    
  2276.  
  2277.     if ( @qv_value_replication != @qv_replication_unlimited ) and ( UPPER(@publisher) <> UPPER(@@servername) )
  2278.     begin
  2279.         -- remote dist publisher is not supported on this server version
  2280.         raiserror(21041,16,-1)
  2281.         return (1)
  2282.     end
  2283.  
  2284.  
  2285.     -- Set default security
  2286.     IF @security_mode IS NULL
  2287.     BEGIN
  2288.         IF (UPPER(@publisher) = UPPER(@@SERVERNAME) and ( platform() & @platform_nt = @platform_nt ) )
  2289.             SELECT @security_mode = 1
  2290.         ELSE
  2291.             SELECT @security_mode = 0
  2292.     END
  2293.  
  2294.     /* 
  2295.     ** Check for invalid security mode
  2296.     */
  2297.     IF @security_mode < 0 OR @security_mode > 1
  2298.         BEGIN
  2299.             RAISERROR(14109, 16, -1)
  2300.             return (1)
  2301.         END
  2302.  
  2303.     IF (UPPER(@publisher) = UPPER(@@SERVERNAME) and ( @platform_nt != platform() & @platform_nt ) and @security_mode = 1)
  2304.     BEGIN
  2305.         RAISERROR(21038, 16, -1)
  2306.         RETURN (1)
  2307.     END
  2308.  
  2309.     -- Encrypt the password
  2310.     select @enc_password = @password
  2311.     IF @encrypted_password = 0
  2312.     BEGIN
  2313.         EXEC @retcode = master.dbo.xp_repl_encrypt @enc_password OUTPUT
  2314.         IF @@error <> 0 OR @retcode <> 0
  2315.             return 1
  2316.     END
  2317.  
  2318.     -- Validate the working directory 
  2319.     -- Remove heading and trailing spaces
  2320.     select @working_directory = RTRIM(LTRIM(@working_directory))
  2321.     
  2322.     -- if the last char is '\', remove it.
  2323.     if substring(@working_directory, len(@working_directory),1) = '\'
  2324.         select @working_directory = substring(@working_directory, 1,
  2325.             len(@working_directory)-1)
  2326.  
  2327.     -- Don't do validation if it is a UNC path due to security problem.
  2328.     -- If the server is started as a service using local system account, we
  2329.     -- don't have access to the UNC path.
  2330.     if substring(@working_directory, 1,2) <> '\\'
  2331.     begin
  2332.         select @command = 'dir "' + fn_escapecmdshellsymbolsremovequotes(@working_directory) collate database_default + '"'
  2333.         exec @retcode = master..xp_cmdshell @command, 'no_output'
  2334.         if @@error <> 0
  2335.             return (1)
  2336.         if @retcode <> 0 
  2337.         begin
  2338.             raiserror (21037, 16, -1, @working_directory)
  2339.             return (1)
  2340.         end
  2341.     end
  2342.  
  2343.     /*
  2344.     ** Parameter Check:  @trusted
  2345.     */
  2346.  
  2347.     if @trusted is null
  2348.     begin
  2349.         if UPPER(@publisher) = UPPER(@@servername)
  2350.             select @trusted = 'false'
  2351.         else
  2352.             select @trusted = 'true'
  2353.     end
  2354.  
  2355.     IF LOWER(@trusted collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  2356.         BEGIN
  2357.             RAISERROR (14148, 16, -1, '@trusted')
  2358.             RETURN (1)
  2359.         END
  2360.  
  2361.     IF LOWER(@trusted collate SQL_Latin1_General_CP1_CS_AS) = 'true' SELECT @trusted_id = 1
  2362.     ELSE SELECT @trusted_id = 0
  2363.  
  2364.     /*
  2365.     ** Check to make sure this is a distributor
  2366.     */
  2367.     IF NOT EXISTS (SELECT * FROM master..sysservers
  2368.               WHERE UPPER(datasource) = UPPER(@@SERVERNAME) collate database_default
  2369.                  AND srvstatus & 8 <> 0)
  2370.     BEGIN
  2371.         RAISERROR (14114, 16, -1, @@SERVERNAME)
  2372.         return (1)
  2373.     END
  2374.  
  2375.     /*
  2376.     ** Check if database is configured as a distributor database
  2377.     */
  2378.     IF NOT EXISTS (SELECT * FROM msdb..MSdistributiondbs WHERE name = @distribution_db collate database_default)
  2379.     BEGIN
  2380.         RAISERROR (14117, 16, -1, @distribution_db)
  2381.         return (1)
  2382.     END
  2383.  
  2384.     /* Check if publisher is already defined. */
  2385.     IF EXISTS (SELECT *
  2386.          FROM msdb..MSdistpublishers
  2387.         WHERE UPPER(name) = UPPER(@publisher) collate database_default)
  2388.  
  2389.     BEGIN
  2390.         RAISERROR (14074, 16, -1, @publisher)
  2391.         RETURN (1)
  2392.     END
  2393.  
  2394.  
  2395.  
  2396.     IF NOT EXISTS (SELECT *
  2397.              FROM master..sysservers
  2398.             WHERE UPPER(srvname) = UPPER(@publisher) collate database_default)
  2399.  
  2400.     /* Add the server if it does not exist. */
  2401.     BEGIN
  2402.         EXECUTE @retcode = dbo.sp_addserver @publisher
  2403.         IF @@error <> 0 OR @retcode <> 0
  2404.         BEGIN
  2405.             RAISERROR (14075, 16, -1)
  2406.             GOTO UNDO
  2407.         END
  2408.         SELECT @server_added = 1
  2409.     END
  2410.     ELSE
  2411.     BEGIN
  2412.         SELECT @publisher = fn_getpersistedservernamecasevariation(@publisher) collate database_default
  2413.     END
  2414.      
  2415.     /*
  2416.     ** Set the Active  value.
  2417.     ** If the @publisher is local, set it to true.
  2418.     ** Otherwise, set it to false
  2419.     */
  2420.     IF UPPER(@publisher) = UPPER(@@SERVERNAME)
  2421.         SELECT @active_value = 1
  2422.     ELSE
  2423.         SELECT @active_value = 0
  2424.  
  2425.  
  2426.     DELETE msdb.dbo.MSdistpublishers where UPPER(name) = UPPER(@publisher) collate database_default
  2427.     IF @@ERROR <> 0
  2428.     BEGIN
  2429.         GOTO UNDO       
  2430.     END
  2431.  
  2432.     INSERT INTO msdb.dbo.MSdistpublishers VALUES (
  2433.         @publisher, @distribution_db, @working_directory,
  2434.         @security_mode, @login, @enc_password, @active_value, @trusted_id, @thirdparty_flag)
  2435.     IF @@ERROR <> 0
  2436.     BEGIN
  2437.         GOTO UNDO       
  2438.     END
  2439.  
  2440.     -- Add distributor_admin to distribution_admin non trusted mapping
  2441.     exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, null, 
  2442.         'distributor_admin'
  2443.     if( @fExists = 0 )
  2444.     BEGIN
  2445.  
  2446.         EXECUTE @retcode = dbo.sp_addremotelogin @publisher, 'distributor_admin', 
  2447.             'distributor_admin'
  2448.         IF @@error <> 0 OR @retcode <> 0
  2449.         BEGIN
  2450.             RAISERROR (14075, 16, -1)
  2451.             GOTO UNDO
  2452.         END
  2453.     END
  2454.  
  2455.     -- For 6x publisher, we still need the trusted sa to sa.
  2456.     -- For 6x publisher upgrading to 7.0, distributor_admin to distributor_admin need to be trusted.
  2457.     -- add remotelogin of SA if it doesn't already exist
  2458.     -- If there's a mapping for remote login sa already, we cannot map it to distributor_admin
  2459.     -- this is the case of server upgraded from 6.5.
  2460.     exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, null, 'sa'
  2461.     if( @fExists = 0 )
  2462.     BEGIN
  2463.         EXECUTE @retcode = dbo.sp_addremotelogin @publisher, 'distributor_admin', 'sa'
  2464.         IF @@error <> 0 OR @retcode <> 0
  2465.         BEGIN
  2466.             RAISERROR (14075, 16, -1)
  2467.             GOTO UNDO
  2468.         END
  2469.     END
  2470.     if @trusted_id = 1
  2471.     begin
  2472.         exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'distributor_admin', 'sa'
  2473.         if( @fExists = 1 )
  2474.         BEGIN
  2475.             EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'sa', trusted, true
  2476.             IF @@error <> 0 OR @retcode <> 0
  2477.             BEGIN
  2478.                 RAISERROR (14075, 16, -1)
  2479.                 GOTO UNDO
  2480.             END
  2481.         END
  2482.  
  2483.         EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'distributor_admin', trusted, true
  2484.         IF @@error <> 0 OR @retcode <> 0
  2485.         BEGIN
  2486.             RAISERROR (14075, 16, -1)
  2487.             GOTO UNDO
  2488.         END
  2489.     END
  2490.  
  2491.  
  2492.     /* Add remotelogin enabling the 'probe' of the publisher to
  2493.     ** RPC for distribution counter information.
  2494.     */
  2495. /* SECURITY ********************************
  2496.     IF NOT EXISTS (SELECT *
  2497.               FROM master..sysremotelogins srl,
  2498.                master..sysservers ss
  2499.              WHERE UPPER(ss.srvname) = UPPER(@publisher) collate database_default
  2500.            AND srl.remoteserverid = ss.srvid
  2501.            AND srl.remoteusername = 'probe'
  2502.        AND srl.suid = 10)    -- 'probe' 
  2503.     exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'probe', 'probe'
  2504.     if (@fExists = 0)
  2505.     BEGIN
  2506.        EXECUTE @retcode = dbo.sp_addremotelogin @publisher, 'probe', 'probe'
  2507.        IF @@error <> 0 OR @retcode <> 0
  2508.        BEGIN
  2509.         RAISERROR (14075, 16, -1)
  2510.         GOTO UNDO
  2511.        END
  2512.     END
  2513. *********************************/
  2514.     
  2515.     RETURN(0)
  2516.  
  2517. UNDO:
  2518.     -- If the server is marked, drop it
  2519.     IF EXISTS (SELECT *
  2520.          FROM msdb..MSdistpublishers
  2521.         WHERE UPPER(name) = UPPER(@publisher) collate database_default)
  2522.         EXEC dbo.sp_dropdistpublisher @publisher
  2523.  
  2524.     IF @server_added = 1
  2525.         EXEC dbo.sp_dropserver @publisher
  2526.  
  2527.     RETURN(1)
  2528. GO
  2529.  
  2530. if exists (select * from sysobjects
  2531.         where type = 'P'
  2532.             and name = 'sp_changedistpublisher')
  2533.     drop procedure sp_changedistpublisher
  2534.  
  2535. raiserror('Creating procedure sp_changedistpublisher', 0,1)
  2536. go
  2537.  
  2538. CREATE PROCEDURE sp_changedistpublisher (
  2539.     @publisher sysname,
  2540.     @property sysname     = NULL,     /* The property to change */
  2541.     @value nvarchar(255)     = NULL      /* The new property value */
  2542.     ) AS
  2543.  
  2544.     SET NOCOUNT ON
  2545.  
  2546.     /*
  2547.     ** Declarations.
  2548.     */
  2549.     DECLARE @retcode int
  2550.     DECLARE @new_database sysname
  2551.     DECLARE @new_security_mode int
  2552.     DECLARE @new_login sysname
  2553.     DECLARE @new_password nvarchar(524)
  2554.     DECLARE @distbit int
  2555.     DECLARE @new_active int
  2556.     DECLARE @new_trusted bit
  2557.     DECLARE @command nvarchar(255)
  2558.     declare @distribdb sysname
  2559.     DECLARE @platform_nt binary
  2560.  
  2561.     SELECT @platform_nt = 0x1
  2562.     SELECT @distbit = 16
  2563.     
  2564.     /*
  2565.     ** Parameter Check:  @property.
  2566.     ** If the @property parameter is NULL, print the options.
  2567.     */
  2568.  
  2569.     IF @property IS NULL
  2570.         BEGIN
  2571.             CREATE TABLE #tab1 (properties sysname collate database_default not null)
  2572.             INSERT INTO #tab1 VALUES ('distribution_db')
  2573.             INSERT INTO #tab1 VALUES ('working_directory')
  2574.             INSERT INTO #tab1 VALUES ('security_mode')
  2575.             INSERT INTO #tab1 VALUES ('login')
  2576.             INSERT INTO #tab1 VALUES ('password')
  2577.             INSERT INTO #tab1 VALUES ('active')
  2578.             INSERT INTO #tab1 VALUES ('trusted')
  2579.             SELECT * FROM #tab1
  2580.             RETURN (0)
  2581.         END
  2582.  
  2583.     /*
  2584.     ** Parameter Check:  @property.
  2585.     ** Check to make sure that @property is a valid property in
  2586.     ** msdb.dbo.MSdistpublishers.
  2587.     */
  2588.     IF @property IS NULL OR LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) NOT IN 
  2589.         ('distribution_db',
  2590.          'working_directory',
  2591.          'security_mode',
  2592.          'login',
  2593.          'password',
  2594.          'active',
  2595.          'trusted')
  2596.         BEGIN
  2597.             RAISERROR (14115, 16, -1, 
  2598.             '''distribution_db'', ''working_directory'', ''security_mode'', ''login'', ''password'', ''active'', or ''trusted''')
  2599.             RETURN (1)
  2600.         END
  2601.  
  2602.     /*
  2603.     ** Check to make sure this is a distributor
  2604.     */
  2605.     IF NOT EXISTS (SELECT * FROM master..sysservers
  2606.               WHERE UPPER(datasource) = UPPER(@@SERVERNAME) collate database_default
  2607.                  AND srvstatus & 8 <> 0)
  2608.     BEGIN
  2609.         RAISERROR (14114, 16, -1, @@SERVERNAME)
  2610.         RETURN(1)
  2611.     END
  2612.  
  2613.     -- Get the distribution db name.
  2614.     select @distribdb = distribution_db from msdb..MSdistpublishers where
  2615.         UPPER(name) = UPPER(@publisher) collate database_default
  2616.  
  2617.     /*
  2618.     ** Change the property.
  2619.     */
  2620.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'distribution_db'
  2621.         BEGIN
  2622.             IF @value IS NULL
  2623.                 BEGIN
  2624.                     RAISERROR (14043, 16, -1, '@value') 
  2625.                     RETURN (1)
  2626.                 END
  2627.  
  2628.             IF @value <> @distribdb and 
  2629.                 EXISTS (SELECT * FROM msdb.dbo.MSdistpublishers WHERE
  2630.                 UPPER(name) = UPPER(@publisher) collate database_default and active = 1)
  2631.             BEGIN
  2632.                 RAISERROR (21046, 16, -1)
  2633.                 RETURN (1)
  2634.             END
  2635.  
  2636.             /*
  2637.             ** Check if database is configured as a distributor database
  2638.             */
  2639.             IF NOT EXISTS (SELECT * FROM master..sysdatabases
  2640.               WHERE name = @value collate database_default
  2641.                  AND category & @distbit <> 0)
  2642.                 BEGIN
  2643.                     RAISERROR (14117, 16, -1, @new_database)
  2644.                     RETURN(1)
  2645.                 END
  2646.  
  2647.             UPDATE msdb..MSdistpublishers SET distribution_db = @value
  2648.                 WHERE UPPER(name) = UPPER(@publisher) collate database_default
  2649.             IF @@error <> 0 
  2650.                 BEGIN
  2651.                     RETURN (1)
  2652.                 END
  2653.         END
  2654.    
  2655.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'working_directory'
  2656.         BEGIN
  2657.             IF @value IS NULL
  2658.                 BEGIN
  2659.                     RAISERROR (14043, 16, -1, '@value') 
  2660.                     RETURN (1)
  2661.                 END
  2662.  
  2663.             
  2664.             -- Validate the working directory 
  2665.             -- Remove heading and trailing spaces
  2666.             select @value = RTRIM(LTRIM(@value))
  2667.  
  2668.             -- if the last char is '\', remove it.
  2669.  
  2670.             if substring(@value, len(@value),1) = '\'
  2671.                 select @value = substring(@value, 1,
  2672.                     len(@value)-1)
  2673.  
  2674.             -- Don't do validation if it is a UNC path due to security problem.
  2675.             -- If the server is started as a service using local system account, we
  2676.             -- don't have access to the UNC path.
  2677.             if substring(@value, 1,2) <> '\\'
  2678.             begin
  2679.                 select @command = 'dir "' + fn_escapecmdshellsymbolsremovequotes(@value) collate database_default + N'"'
  2680.                 exec @retcode = master..xp_cmdshell @command, 'no_output'
  2681.                 if @@error <> 0
  2682.                     return 1
  2683.                 if @retcode <> 0 
  2684.                 begin
  2685.                     raiserror (21037, 16, -1, @value)
  2686.                     return 1
  2687.                 end
  2688.             end
  2689.  
  2690.             UPDATE msdb..MSdistpublishers SET working_directory = @value
  2691.                 WHERE UPPER(name) = UPPER(@publisher) collate database_default
  2692.             IF @@error <> 0 
  2693.                 BEGIN
  2694.                     RETURN (1)
  2695.                 END
  2696.         END
  2697.  
  2698.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'security_mode'
  2699.         BEGIN
  2700.             IF @value IS NULL
  2701.                 BEGIN
  2702.                     RAISERROR (14043, 16, -1, '@value') 
  2703.                     RETURN (1)
  2704.                 END
  2705.  
  2706.             /*
  2707.             ** Set the SecurityMode registry key value
  2708.             */
  2709.             SELECT @new_security_mode = CONVERT(int, @value)
  2710.  
  2711.             /* 
  2712.             ** Check for invalid values 
  2713.             */
  2714.             IF @new_security_mode < 0 OR @new_security_mode > 1
  2715.                 BEGIN
  2716.                     RAISERROR(14109, 16, -1)
  2717.                     RETURN (1)
  2718.                 END
  2719.  
  2720.             IF (UPPER(@publisher) = UPPER(@@SERVERNAME) and ( @platform_nt != platform() & @platform_nt ) and @new_security_mode = 1)
  2721.             BEGIN
  2722.                 RAISERROR(21038, 16, -1)
  2723.                 RETURN (1)
  2724.             END
  2725.  
  2726.             UPDATE msdb..MSdistpublishers SET security_mode = @new_security_mode
  2727.                 WHERE UPPER(name) = UPPER(@publisher) collate database_default
  2728.             IF @@error <> 0 
  2729.                 BEGIN
  2730.                     RETURN (1)
  2731.                 END
  2732.         END
  2733.  
  2734.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'login'
  2735.         BEGIN
  2736.             IF @value IS NULL
  2737.                 BEGIN
  2738.                     RAISERROR (14043, 16, -1, '@value') 
  2739.                     RETURN (1)
  2740.                 END
  2741.  
  2742.             /*
  2743.             ** Set the Login registry key value
  2744.             */
  2745.             SELECT @new_login = CONVERT(sysname, @value)
  2746.  
  2747.             UPDATE msdb..MSdistpublishers SET login = @new_login
  2748.                 WHERE UPPER(name) = UPPER(@publisher) collate database_default
  2749.             IF @@error <> 0 
  2750.                 BEGIN
  2751.                     RETURN (1)
  2752.                 END
  2753.         END
  2754.  
  2755.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'password'
  2756.         BEGIN
  2757.             /*
  2758.             ** Set the Password registry key value
  2759.             */
  2760.             SELECT @new_password = CONVERT(nvarchar(524), @value)
  2761.  
  2762.             -- Encrypt the password
  2763.             EXEC @retcode = master.dbo.xp_repl_encrypt @new_password OUTPUT
  2764.             IF @@error <> 0 OR @retcode <> 0
  2765.                 RETURN (1)
  2766.  
  2767.             UPDATE msdb..MSdistpublishers SET password = @new_password
  2768.                 WHERE UPPER(name) = UPPER(@publisher) collate database_default
  2769.             IF @@error <> 0 
  2770.                 BEGIN
  2771.                     RETURN (1)
  2772.                 END
  2773.          END
  2774.  
  2775.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'active'
  2776.         BEGIN
  2777.             /*
  2778.             ** Check for a valid  value.
  2779.             */
  2780.  
  2781.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  2782.             BEGIN
  2783.                 RAISERROR (14137, 16, -1)
  2784.                 RETURN (1)
  2785.             END
  2786.  
  2787.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  2788.             begin
  2789.                 -- Clean up the database in case of the remote publisher is reinstalling publishing.
  2790.                 SELECT @command = @distribdb + '.dbo.sp_MSdistpublisher_cleanup'
  2791.                 exec @retcode = @command @publisher
  2792.                 if @retcode <> 0 or @@error <> 0
  2793.                     return 1
  2794.                 SELECT @new_active = 1
  2795.             end
  2796.             ELSE
  2797.             BEGIN
  2798.                 SELECT @new_active = 0
  2799.             END
  2800.  
  2801.             /*
  2802.             ** Set the Active registry key value
  2803.             */
  2804.             UPDATE msdb..MSdistpublishers SET active = @new_active
  2805.                 WHERE UPPER(name) = UPPER(@publisher) collate database_default
  2806.             IF @@error <> 0
  2807.                 BEGIN
  2808.                     RETURN (1)
  2809.                 END
  2810.  
  2811.         END
  2812.  
  2813.     IF LOWER(@property collate SQL_Latin1_General_CP1_CS_AS) = 'trusted'
  2814.         BEGIN
  2815.             /*
  2816.             ** Check for a valid  value.
  2817.             */
  2818.  
  2819.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) NOT IN ('true', 'false')
  2820.             BEGIN
  2821.                 RAISERROR (14137, 16, -1)
  2822.                 RETURN (1)
  2823.             END
  2824.  
  2825.             declare @fExists int
  2826.  
  2827.             IF LOWER(@value collate SQL_Latin1_General_CP1_CS_AS) = 'true'
  2828.             begin
  2829.                 SELECT @new_trusted = 1
  2830.                 exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'distributor_admin', 'sa'
  2831.                 if( @fExists = 1 )
  2832.                 BEGIN
  2833.                     EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'sa', trusted, true
  2834.                     IF @@error <> 0 OR @retcode <> 0
  2835.                     BEGIN
  2836.                         RAISERROR (14075, 16, -1)
  2837.                         RETURN (1)
  2838.                     END
  2839.                 END
  2840.  
  2841.  
  2842.                 EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 
  2843.                     'distributor_admin', trusted, true
  2844.                 IF @@error <> 0 OR @retcode <> 0
  2845.                 BEGIN
  2846.                     RAISERROR (14075, 16, -1)
  2847.                     RETURN (1)
  2848.                 END
  2849.             end
  2850.             ELSE
  2851.             BEGIN
  2852.                 SELECT @new_trusted = 0
  2853.      
  2854.                 exec @fExists = dbo.sp_MSIfExistsRemoteLogin @publisher, 'distributor_admin', 'sa'
  2855.                 if( @fExists = 1 )
  2856.                 BEGIN
  2857.                     EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin', 'sa', trusted, false
  2858.                     IF @@error <> 0 OR @retcode <> 0
  2859.                     BEGIN
  2860.                         RAISERROR (14075, 16, -1)
  2861.                         RETURN (1)
  2862.                     END
  2863.                 END
  2864.  
  2865.  
  2866.                 EXECUTE @retcode = dbo.sp_remoteoption @publisher, 'distributor_admin',
  2867.                     'distributor_admin', trusted, 'false'
  2868.                 IF @@error <> 0 OR @retcode <> 0
  2869.                 BEGIN
  2870.                     RAISERROR (14075, 16, -1)
  2871.                     RETURN (1)
  2872.                 END
  2873.             END
  2874.  
  2875.             /*
  2876.             ** Set the trusted property
  2877.             */
  2878.             UPDATE msdb..MSdistpublishers SET trusted = @new_trusted
  2879.                 WHERE UPPER(name) = UPPER(@publisher) collate database_default
  2880.             IF @@error <> 0
  2881.                 BEGIN
  2882.                     RETURN (1)
  2883.                 END
  2884.         END
  2885.  
  2886.   
  2887.     /*
  2888.     ** Return succeed.
  2889.     */
  2890.     RAISERROR (21035, 10, -1, @property)
  2891.  
  2892. DONE:    
  2893.     RETURN (0)
  2894. go
  2895.  
  2896. if exists (select * from sysobjects
  2897.         where type = 'P'
  2898.             and name = 'sp_MScopyscriptfile')
  2899.     drop procedure sp_MScopyscriptfile
  2900. go
  2901. create proc sp_MScopyscriptfile (
  2902.     @scriptfile nvarchar(4000), 
  2903.     @cmd nvarchar(4000) OUTPUT
  2904. )
  2905. as
  2906. declare @directory nvarchar(4000)
  2907. declare @filename nvarchar(1024)
  2908. declare @subdirectory nvarchar(1024)
  2909. declare @retcode int
  2910.  
  2911. IF @scriptfile IS NULL
  2912. BEGIN
  2913.     RAISERROR (14043, 16, -1, '@scriptfile')
  2914.     RETURN (1)
  2915. END
  2916. -- Create the directory on distributor to store script.
  2917. exec sp_helpdistributor @directory=@directory OUTPUT
  2918. select @subdirectory = convert(nvarchar(64), GetDate(), 121)
  2919. select @subdirectory = replace(@subdirectory, N'-', N'')
  2920. select @subdirectory = replace(@subdirectory, N' ', N'')
  2921. select @subdirectory = replace(@subdirectory, N':', N'')
  2922. select @subdirectory = replace(@subdirectory, N'.', N'')
  2923. if(right(@directory, 1) = N'\')
  2924.     select @directory = @directory + @subdirectory
  2925. else
  2926.     select @directory = @directory + N'\' + @subdirectory
  2927. select @cmd = N'md "' + fn_escapecmdshellsymbolsremovequotes(@directory) collate database_default + '"'
  2928. exec @retcode = master..xp_cmdshell @cmd, NO_OUTPUT
  2929. if(@retcode <> 0)
  2930. begin
  2931.     raiserror(21330, 16, -1, @cmd)
  2932.     return (1)
  2933. end
  2934.  
  2935. -- Copy script to distributor
  2936. select @cmd = N'copy "' + fn_escapecmdshellsymbolsremovequotes(@scriptfile) collate database_default + N'" "' + fn_escapecmdshellsymbolsremovequotes(@directory) collate database_default + N'"'
  2937. exec @retcode = master..xp_cmdshell @cmd, NO_OUTPUT
  2938. if(@retcode <> 0)
  2939. begin 
  2940.     raiserror(21331, 16, -1, @cmd)
  2941.     return (1)
  2942. end
  2943.  
  2944. -- Prepare command, to be posted to log
  2945. select @filename = right(@scriptfile, charindex(N'\', reverse(@scriptfile)))
  2946. if(left(@filename, 1) = N'\')    
  2947.     select @cmd = @directory + @filename
  2948. else
  2949.     select @cmd = @directory + N'\' + @filename
  2950. go
  2951. exec sp_MS_marksystemobject sp_MScopyscriptfile
  2952. go
  2953.  
  2954.  
  2955. --------------------------------------------------------------------------------
  2956. --.    System objects (rladmin.sql)
  2957. --------------------------------------------------------------------------------
  2958. if exists (select * from sysobjects
  2959.         where type in ('P ') 
  2960.             and name = 'sp_MSremove_userscript')
  2961.     drop procedure sp_MSremove_userscript
  2962. go
  2963.  
  2964. create procedure sp_MSremove_userscript(
  2965. @pubid                uniqueidentifier,
  2966. @drop_publication    bit = 0
  2967. )as
  2968.     declare @retention            int
  2969.     declare @last_snapshot        datetime
  2970.     declare @post_snapshot_ver    int
  2971.     declare @post_snapshot_type    int
  2972.     declare @user_script_type    int
  2973.     declare @retcode            int
  2974.     declare @len                int
  2975.  
  2976.     declare @file_path            nvarchar(4000)
  2977.     declare @delfile_cmd        nvarchar(4000)
  2978.     declare @rmdir_cmd            nvarchar(4000)
  2979.     
  2980.     select @post_snapshot_type=52
  2981.     select @user_script_type=46
  2982.     
  2983.     if not exists (select * from sysmergeschemachange where pubid=@pubid and schematype=@user_script_type)
  2984.         return (0)
  2985.     select @retention=retention from sysmergepublications where pubid=@pubid
  2986.     select @last_snapshot=last_validated from sysmergesubscriptions where pubid=@pubid and subid=@pubid
  2987.  
  2988.     --I do not want to remove  script files by setting retention to 0
  2989.     if (@retention=0 or dateadd(day, -@retention, getdate()) < @last_snapshot) and @drop_publication = 0
  2990.         return (0)
  2991.  
  2992.     select @post_snapshot_ver=schemaversion from sysmergeschemachange 
  2993.         where schematype=@post_snapshot_type and pubid=@pubid
  2994.         
  2995.     --only get those script that can be safely removed
  2996.     
  2997.     declare #per_script cursor local fast_forward for
  2998.         select schematext from sysmergeschemachange 
  2999.             where pubid=@pubid and schematype=@user_script_type 
  3000.             and (schemaversion<@post_snapshot_ver or @drop_publication = 1)
  3001.     open #per_script
  3002.     fetch #per_script into @file_path
  3003.     while (@@fetch_status<>-1)
  3004.     begin
  3005.     if(left(@file_path, 1) = N'0' or left(@file_path, 1) = N'1')
  3006.         select @file_path = right(@file_path, len(@file_path) - 1)
  3007.         select @delfile_cmd = N'del "' + fn_escapecmdshellsymbolsremovequotes(@file_path) collate database_default + N'"'
  3008.         EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT
  3009.         if @@ERROR<>0
  3010.             goto FAILURE
  3011.         select @len=CHARINDEX ( '\' , reverse(@file_path) ) 
  3012.         select @file_path=SUBSTRING(@file_path , 1 , len(@file_path)-@len + 1)
  3013.         
  3014.         select @delfile_cmd = N'rmdir "' + fn_escapecmdshellsymbolsremovequotes(@file_path) collate database_default + N'"'
  3015.         EXEC @retcode = master..xp_cmdshell @delfile_cmd, NO_OUTPUT
  3016.         if @@ERROR<>0
  3017.             goto FAILURE
  3018.         fetch next from #per_script into @file_path
  3019.     end
  3020.     
  3021.     close #per_script
  3022.     deallocate #per_script
  3023.     return (0)
  3024. FAILURE:
  3025.     close #per_script
  3026.     deallocate #per_script
  3027.     return (1)
  3028. go
  3029. EXEC dbo.sp_MS_marksystemobject 'sp_MSremove_userscript'
  3030. grant execute on sp_MSremove_userscript to public
  3031. go
  3032.  
  3033. exec sp_MS_upd_sysobj_category 2
  3034. go
  3035.  
  3036. exec sp_configure 'allow updates',0
  3037. go
  3038.  
  3039. reconfigure with override
  3040. go
  3041.  
  3042. --------------------------------------------------------------------------------
  3043. -- qfe361327
  3044. --------------------------------------------------------------------------------
  3045. --------------------------------------------------------------------------------
  3046. -- VERIFY Server is started in single-user-mode (catalog-updates enabled), and
  3047. --    start marking of system-objects.
  3048. --------------------------------------------------------------------------------
  3049. use master
  3050. go
  3051.  
  3052. dump tran master with no_log
  3053. go
  3054.  
  3055. exec dbo.sp_configure 'allow updates',1
  3056. go
  3057. reconfigure with override
  3058. go
  3059.  
  3060. set ANSI_NULLS off
  3061.  
  3062. exec sp_MS_upd_sysobj_category 1
  3063. go
  3064.  
  3065.  
  3066. if exists (select * from sysobjects
  3067.         where name = 'xp_execresultset')
  3068.     revoke execute on dbo.xp_execresultset to public
  3069.  
  3070. if exists (select * from sysobjects
  3071.         where name = 'xp_displayparamstmt')
  3072.     revoke execute on dbo.xp_displayparamstmt to public
  3073.  
  3074. if exists (select * from sysobjects
  3075.         where name = 'xp_printstatements')
  3076.     revoke execute on dbo.xp_printstatements to public
  3077.  
  3078.  
  3079. exec sp_MS_upd_sysobj_category 2
  3080. go
  3081.  
  3082. exec sp_configure 'allow updates',0
  3083. go
  3084.  
  3085. reconfigure with override
  3086. go
  3087.  
  3088.  
  3089. --------------------------------------------------------------------------------
  3090. -- qfe361713
  3091. --------------------------------------------------------------------------------
  3092.  
  3093. --------------------------------------------------------------
  3094. -- BEGIN CHANGES TO REPLCOM.SQL
  3095. --------------------------------------------------------------
  3096. USE master
  3097. go
  3098. if object_id('sp_replproberemoteserver', 'P') is not null
  3099. begin
  3100.     drop procedure sp_replproberemoteserver
  3101. end
  3102. go
  3103. raiserror('Creating procedure sp_replproberemoteserver', 0,1)
  3104. go
  3105. --
  3106. -- Name: sp_replproberemoteserver
  3107. --
  3108. -- Description: This is a lightweight wrapper for calling xp_replproberremsrv
  3109. --              with the added nicety of looking up the agent command line
  3110. --              using the given jobid. This procedure supports two different
  3111. --              modes of operation based on the @no_rpc parameter. If the 
  3112. --              @no_rpc parameter is 1, this procedure will not attempt to make
  3113. --              rpc call to the Distributor. The local mode is mainly useful 
  3114. --              for verifying remote pull subscription agent.
  3115. -- 
  3116. -- Parameters: @remoteservername sysname (mandatory) 
  3117. --             @agent_type nvarchar(16) (optional, default = null) 
  3118. --             @agent_jobid uniqueidentifier (optional default = null)
  3119. --             @no_rpc bit (optional default = 0)
  3120. --
  3121. -- Notes: If @job_id is null, only activation verification will be carried
  3122. --        out.
  3123. --
  3124. -- Security: Execute permission of this procedure is granted to public
  3125. --
  3126. -- Result: 'probe_succeeded' 0 or 1
  3127. --
  3128. -- Returns: 0    - succeeded
  3129. --          <> 0 - failed
  3130. --
  3131. create procedure dbo.sp_replproberemoteserver (
  3132.     @remoteservername sysname,
  3133.     @agent_type       nvarchar(16) = null,
  3134.     @agent_jobid      uniqueidentifier = null,
  3135.     @no_rpc           bit = 0
  3136.     ) 
  3137. as
  3138. begin
  3139.     set nocount on
  3140.     declare @retcode        int
  3141.     declare @commandline    nvarchar(3200)
  3142.     declare @distributor    sysname
  3143.     declare @distributiondb sysname     
  3144.     declare @distproc       nvarchar(255)
  3145.     declare @succeeded      nvarchar(10)
  3146.  
  3147.     select @retcode = 0
  3148.     select @commandline = null
  3149.     select @succeeded = null
  3150.  
  3151.     -- security check, db_owner
  3152.     -- Note that this proc can be called from either a publisher database or
  3153.     -- a subscriber database
  3154.     exec @retcode = dbo.sp_MSreplcheck_publish
  3155.     if @@error <> 0 or @retcode <> 0
  3156.         return (1)
  3157.  
  3158.     if @agent_type is null
  3159.     begin
  3160.         select @agent_type = 'distribution'
  3161.     end
  3162.     
  3163.     -- @remoteservername cannot be null or empty
  3164.     select @remoteservername = rtrim(ltrim(@remoteservername))
  3165.     if @remoteservername is null or
  3166.        @remoteservername = N''
  3167.     begin
  3168.         raiserror(21263,16,-1,'@remoteservername')
  3169.         return 1
  3170.     end     
  3171.     
  3172.     -- @agent_type must be 'distribution' or 'merge'
  3173.     if @agent_type not in (N'distribution', N'merge')
  3174.     begin
  3175.         raiserror(21182,16,-1) 
  3176.         return 1
  3177.     end
  3178.  
  3179.     -- Get Distributor information
  3180.     if @no_rpc = 0
  3181.     begin
  3182.         exec @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor output,
  3183.                                           @distribdb = @distributiondb output
  3184.         if @@error <> 0 or @retcode <> 0
  3185.             return 1
  3186.     end
  3187.     else
  3188.     begin
  3189.         select @distributor = @@servername
  3190.     end
  3191.  
  3192.     if upper(@@servername) <> upper(@distributor)
  3193.     begin
  3194.         select @distproc = ltrim(rtrim(@distributor)) + '.' + 
  3195.             'master.dbo.sp_replproberemoteserver'
  3196.         exec @retcode = @distproc @remoteservername, 
  3197.                                   @agent_type, 
  3198.                                   @agent_jobid, 
  3199.                                   1
  3200.         return @retcode
  3201.     end        
  3202.     else
  3203.     begin
  3204.         -- If the given @job_id is not null, try to get
  3205.         -- the agent command line
  3206.         if @agent_jobid is not null 
  3207.         begin
  3208.             select @commandline = fn_replgetagentcommandlinefromjobid(
  3209.                 @agent_type,
  3210.                 @agent_jobid) collate database_default
  3211.  
  3212.             if @commandline is null
  3213.             begin
  3214.                 raiserror(21361,6,-1, @agent_type) 
  3215.                 select 'probe_succeeded' = 0
  3216.                 return 1
  3217.             end
  3218.  
  3219.         end 
  3220.  
  3221.         exec @retcode = master.dbo.xp_replproberemsrv 
  3222.             @remoteservername, 
  3223.             @agent_type, 
  3224.             @succeeded output,
  3225.             @commandline 
  3226.  
  3227.         if lower(@succeeded collate SQL_Latin1_General_CP1_CS_AS) = N'true'  
  3228.             select 'probe_succeeded' = 1
  3229.         else
  3230.             select 'probe_succeeded' = 0
  3231.  
  3232.         return @retcode
  3233.     end
  3234.  
  3235.     select 'probe_succeeded' = 0
  3236.  
  3237.     return 1
  3238. end
  3239. go
  3240.  
  3241. exec sp_MS_marksystemobject sp_replproberemoteserver
  3242. go
  3243. grant execute on dbo.sp_replproberemoteserver to public
  3244. go
  3245.  
  3246. revoke execute on dbo.xp_replproberemsrv to public
  3247. go
  3248.  
  3249. --------------------------------------------------------------------------------
  3250. -- QFE361403 changes - repltran.sql and replsys.sql
  3251. --------------------------------------------------------------------------------
  3252. set ANSI_NULLS off
  3253. go
  3254.  
  3255. exec dbo.sp_configure 'update',1
  3256. go
  3257. reconfigure with override
  3258. go
  3259.  
  3260. --------------------------------------------------------------------------------
  3261. --. sp_MSisnonpkukupdateinconflict
  3262. --------------------------------------------------------------------------------
  3263.  
  3264. if exists (select * from sysobjects
  3265.     where type = 'P' and name = 'sp_MSisnonpkukupdateinconflict')
  3266. drop procedure sp_MSisnonpkukupdateinconflict
  3267. go
  3268. raiserror('Creating procedure sp_MSisnonpkukupdateinconflict', 0,1)
  3269. go
  3270. create proc sp_MSisnonpkukupdateinconflict (
  3271.     @pubid int
  3272.     ,@artid int
  3273.     ,@bitmap varbinary(4000)
  3274. )
  3275. as
  3276. begin
  3277.     declare @retcode int
  3278.         ,@columns binary(32)
  3279.         ,@tabname sysname
  3280.         ,@tabid int
  3281.         ,@indid int
  3282.         ,@indkey int
  3283.         ,@key sysname
  3284.         ,@colid int
  3285.         ,@isset int
  3286.         ,@artcol int
  3287.         ,@bytepos int
  3288.         ,@bitpos int
  3289.     declare @ukcoltab table(ukindex int identity, keyname sysname collate database_default not null)
  3290.  
  3291.     --
  3292.     -- security check
  3293.     --
  3294.     exec @retcode = dbo.sp_MSreplcheck_publish
  3295.     if @@ERROR != 0 or @retcode != 0
  3296.         return (1)
  3297.     --
  3298.     -- initalize and validate
  3299.     --
  3300.     select @columns = [columns]
  3301.         ,@tabid = objid
  3302.         ,@artcol = 0
  3303.     from dbo.sysarticles
  3304.     where (artid = @artid) and (pubid = @pubid)
  3305.     --
  3306.     -- validate article
  3307.     --
  3308.     if (@tabid is null)
  3309.     begin
  3310.         raiserror(21344, 16, -1, '@pubid, @artid')
  3311.         return -1
  3312.     end
  3313.     --
  3314.     -- the table should have non PK unique keys
  3315.     --
  3316.     exec @retcode = dbo.sp_repltablehasnonpkuniquekey @tabid
  3317.     if (@retcode != 1)
  3318.     begin
  3319.         return 0
  3320.     end
  3321.     --
  3322.     -- get fully qualified table
  3323.     --
  3324.     select @tabname = QUOTENAME(user_name(OBJECTPROPERTY(@tabid, 'OwnerId'))) collate database_default 
  3325.             + N'.' + QUOTENAME(object_name( @tabid )) collate database_default
  3326.  
  3327.     --
  3328.     -- get the non PK unique indices
  3329.     --
  3330.     declare #hcindid cursor local fast_forward for
  3331.         select indid from sysindexes 
  3332.         where id = @tabid 
  3333.             and (status & 2) != 0
  3334.             and (status & 2048) = 0
  3335.             and indid > 0 and indid < 255
  3336.         order by indid asc
  3337.     open #hcindid
  3338.     fetch #hcindid into @indid
  3339.     while (@@fetch_status != -1)
  3340.     begin
  3341.         --
  3342.         -- create an enumeration of all the columns 
  3343.         -- that are part of selected unique index
  3344.         --
  3345.         select @indkey = 1
  3346.         while (@indkey <= 16)
  3347.         begin
  3348.             select @key = index_col( @tabname, @indid, @indkey )
  3349.             if (@key is null)
  3350.                 break
  3351.             else
  3352.             begin
  3353.                 if not exists (select * from @ukcoltab where keyname = @key)
  3354.                     insert into @ukcoltab(keyname) values(@key)
  3355.             end
  3356.             select @indkey = @indkey + 1
  3357.         end
  3358.         --
  3359.         -- fetch next index
  3360.         --
  3361.         fetch #hcindid into @indid
  3362.     end
  3363.     close #hcindid
  3364.     deallocate #hcindid
  3365.     --
  3366.     -- now walk through each article col and if it is
  3367.     -- a part of any of the unique keys, then check if the update bitmap bit 
  3368.     -- corresponding to any article column is set
  3369.     --
  3370.     declare #hccolid cursor local fast_forward for
  3371.         select colid, [name] from dbo.syscolumns 
  3372.         where id = @tabid order by colid asc
  3373.  
  3374.     open #hccolid
  3375.     fetch #hccolid INTO @colid, @key
  3376.     while (@@fetch_status != -1)
  3377.     begin
  3378.         exec @isset = dbo.sp_isarticlecolbitset @colid, @columns
  3379.         if (@isset != 0)
  3380.         begin
  3381.             --
  3382.             -- this column is part of the article
  3383.             --
  3384.             select @artcol = @artcol + 1
  3385.             if exists (select * from @ukcoltab where keyname = @key)
  3386.             begin
  3387.                 --
  3388.                 -- this column is part of an unique key
  3389.                 --
  3390.                 select @bytepos = 1 + (@artcol-1) / 8 
  3391.                     ,@bitpos = power(2, (@artcol-1) % 8 )
  3392.                 --
  3393.                 -- if the update bitmap has bit set then
  3394.                 -- then it is a nonPK key update
  3395.                 --
  3396.                 if ((substring(@bitmap, @bytepos, 1) & @bitpos) = @bitpos)
  3397.                     return 1
  3398.             end
  3399.         end        
  3400.         --
  3401.         -- get the next column
  3402.         --
  3403.         fetch #hccolid INTO @colid, @key
  3404.     end
  3405.     close #hccolid
  3406.     deallocate #hccolid
  3407.     --
  3408.     -- if we have reached here then it mean the update does not
  3409.     -- affect PK columns, cleanup and return
  3410.     --
  3411.     return 0
  3412. end
  3413. go
  3414. exec dbo.sp_MS_marksystemobject sp_MSisnonpkukupdateinconflict
  3415. go
  3416. grant execute on dbo.sp_MSisnonpkukupdateinconflict  to public
  3417. go
  3418.  
  3419. --------------------------------------------------------------------------------
  3420. --. sp_scriptpubwinsrefreshcursorvars
  3421. --------------------------------------------------------------------------------
  3422.  
  3423. if exists (select * from sysobjects
  3424.     where type = 'P' and name = 'sp_scriptpubwinsrefreshcursorvars')
  3425. drop procedure sp_scriptpubwinsrefreshcursorvars
  3426. go
  3427. raiserror('Creating procedure sp_scriptpubwinsrefreshcursorvars', 0,1)
  3428. go
  3429. create procedure sp_scriptpubwinsrefreshcursorvars 
  3430. (
  3431.     @objid int                -- object id
  3432. )
  3433. as
  3434. begin
  3435.     declare
  3436.             @rc           int
  3437.             ,@cmd nvarchar(4000)
  3438.             ,@colname      sysname
  3439.             ,@ccoltype     sysname
  3440.             ,@this_col     int
  3441.             ,@typestring nvarchar(100)
  3442.              ,@spacer nvarchar(5)
  3443.             ,@isset int
  3444.             ,@pkcolumns varbinary(32)
  3445.  
  3446.     select @cmd = N'
  3447.         declare '
  3448.         ,@spacer = N''
  3449.     exec dbo.sp_getarticlepkcolbitmap @objid, @pkcolumns output
  3450.     declare #hccolid cursor local fast_forward for 
  3451.         select colid from syscolumns where id = @objid order by colid asc
  3452.     open #hccolid
  3453.     fetch #hccolid into @this_col
  3454.     while (@@fetch_status != -1)
  3455.     begin
  3456.         exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
  3457.         if @isset != 0 and exists ( select name from syscolumns where id=@objid and colid=@this_col and iscomputed !=1 ) 
  3458.         begin
  3459.             exec dbo.sp_gettypestring @objid, @this_col, @typestring output
  3460.             select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @this_col ) + N' ' + @typestring 
  3461.                     ,@spacer = N','
  3462.  
  3463.             if len( @cmd ) > 3000
  3464.             begin
  3465.                 insert into #proctext(procedure_text) values( @cmd )
  3466.                 select @cmd = N''
  3467.             end
  3468.         end
  3469.         fetch #hccolid into @this_col
  3470.     end
  3471.     close #hccolid
  3472.     deallocate #hccolid
  3473.     if len(@cmd) > 0
  3474.         insert into #proctext(procedure_text) values( @cmd )
  3475.     --
  3476.     -- all done
  3477.     --
  3478.     return 0
  3479. end
  3480. go
  3481. exec dbo.sp_MS_marksystemobject sp_scriptpubwinsrefreshcursorvars
  3482. go
  3483.  
  3484. --------------------------------------------------------------------------------
  3485. --. sp_MSscriptdelconflictfinder
  3486. --------------------------------------------------------------------------------
  3487.  
  3488. if exists (select * from sysobjects
  3489.     where type = 'P' and name = 'sp_MSscriptdelconflictfinder')
  3490. drop procedure sp_MSscriptdelconflictfinder
  3491. go
  3492. raiserror('Creating procedure sp_MSscriptdelconflictfinder', 0,1)
  3493. go
  3494. create procedure sp_MSscriptdelconflictfinder 
  3495. (
  3496.     @publication sysname        -- publication name
  3497.     ,@article sysname            -- article name
  3498.     ,@objid int                -- object id
  3499.     ,@columns binary(32)        -- columns replicated
  3500. )
  3501. as
  3502. begin
  3503.     declare 
  3504.             @rc int
  3505.             ,@cmd nvarchar(4000)
  3506.             ,@artid int
  3507.             ,@pubid int
  3508.             ,@qualname nvarchar(512)
  3509.             ,@fhasnonpkuniquekeys int
  3510.  
  3511.     --
  3512.     -- initialize the vars we will use
  3513.     --
  3514.     select @pubid = pubid 
  3515.     from syspublications 
  3516.     where name = @publication
  3517.     select @artid = artid
  3518.     from sysarticles 
  3519.     where name = @article 
  3520.         and pubid = @pubid
  3521.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  3522.     --
  3523.     --  check if this article has non PK unique keys
  3524.     --
  3525.     exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
  3526.     --
  3527.     -- start scripting
  3528.     --
  3529.     select @cmd = N'
  3530.     '+N'--
  3531.     '+N'-- --------------------------------------------------------------------
  3532.     '+N'-- This is the crux of the proc for conflict resolution 
  3533.     '+N'-- This code block is essentially a state machine
  3534.     '+N'-- where we ascertain the state of resolution
  3535.     '+N'-- The actions of this resolution varies for the policy
  3536.     '+N'-- The comments for each state outline the policy
  3537.     '+N'-- specific actions 
  3538.     '+N'-- --------------------------------------------------------------------
  3539.     '+N'--
  3540.     '
  3541.     insert into #proctext(procedure_text) values( @cmd )
  3542.     --
  3543.     -- continue scripting
  3544.     --
  3545.     select @cmd = N'
  3546.     if (@execution_mode in (@QPubWins, @QSubWins))
  3547.     begin
  3548.         '+N'--
  3549.         '+N'-- initialize the conflict case
  3550.         '+N'--
  3551.         select @cftcase = 0
  3552.  
  3553.         if (@rowcount = 0)
  3554.         begin
  3555.             '+N'--
  3556.             '+N'-- row was deleted or updated
  3557.             '+N'--'
  3558.     insert into #proctext(procedure_text) values( @cmd )
  3559.     --
  3560.     -- script row exists with OLD_PK
  3561.     --
  3562.     select @cmd = N'
  3563.             if exists (select * from ' + @qualname 
  3564.     insert into #proctext(procedure_text) values( @cmd )
  3565.     exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
  3566.     insert into #proctext(procedure_text) values( N'            )')
  3567.     --
  3568.     -- continue scripting
  3569.     --
  3570.     select @cmd = N'
  3571.             begin
  3572.                 '+N'--
  3573.                 '+N'-- Case 31: Conflict as row was updated
  3574.                 '+N'-- PubWins -----------------------------------------------------------
  3575.                 '+N'-- generate delete + insert compensating action with values for all unique keys 
  3576.                 '+N'-- SubWins -----------------------------------------------------------
  3577.                 '+N'-- delete row with PK
  3578.                 '+N'--
  3579.                 select @cftcase = 31
  3580.             end'
  3581.     insert into #proctext(procedure_text) values( @cmd )
  3582.     --
  3583.     -- continue scripting
  3584.     --
  3585.     select @cmd = N'
  3586.             else
  3587.             begin
  3588.                 '+N'--
  3589.                 '+N'-- Case 33: Conflict as row does not exist
  3590.                 '+N'-- PubWins -----------------------------------------------------------
  3591.                 '+N'-- do nothing
  3592.                 '+N'-- SubWins -----------------------------------------------------------
  3593.                 '+N'-- do nothing
  3594.                 '+N'--
  3595.                 select @cftcase = 33
  3596.             end
  3597.         end'
  3598.     insert into #proctext(procedure_text) values( @cmd )
  3599.     --
  3600.     -- continue scripting
  3601.     --
  3602.     select @cmd = N'
  3603.         else if (@execution_mode = @QPubWins)
  3604.         begin
  3605.             '+N'--
  3606.             '+N'-- we had no conflict for this command
  3607.             '+N'-- We need to process this block only in the Publisher Wins cases
  3608.             '+N'--
  3609.  
  3610.             '+N'--
  3611.             '+N'-- case 30: No conflict - we have to undo the delete
  3612.             '+N'-- PubWins -----------------------------------------------------------
  3613.             '+N'-- generate delete + insert compensating action with values for all unique keys 
  3614.             '+N'-- 
  3615.             select @cftcase = 30
  3616.         end    
  3617.     end'
  3618.     insert into #proctext(procedure_text) values( @cmd )
  3619.     --
  3620.     -- continue scripting
  3621.     --
  3622.     select @cmd = N'
  3623.  
  3624.     '+N'--
  3625.     '+N'-- --------------------------------------------------------------------
  3626.     '+N'-- Now the generation phase
  3627.     '+N'-- Use the conflict case value to decide what to do
  3628.     '+N'-- --------------------------------------------------------------------
  3629.     '+N'--'
  3630.     insert into #proctext(procedure_text) values( @cmd )
  3631.     --
  3632.     -- all done
  3633.     --
  3634.     return 0
  3635. end
  3636. go
  3637. exec dbo.sp_MS_marksystemobject sp_MSscriptdelconflictfinder
  3638. go
  3639.  
  3640. --------------------------------------------------------------------------------
  3641. --. sp_script_insertforcftresolution
  3642. --------------------------------------------------------------------------------
  3643.  
  3644. if exists (select * from sysobjects
  3645.     where type = 'P' and name = 'sp_script_insertforcftresolution')
  3646. drop procedure sp_script_insertforcftresolution
  3647. go
  3648. raiserror('Creating procedure sp_script_insertforcftresolution', 0,1)
  3649. go
  3650. create procedure sp_script_insertforcftresolution 
  3651. (
  3652.     @objid int                -- object id
  3653.     ,@columns binary(32)        -- columns replicated
  3654.     ,@identity_insert bit        -- enable identity insert
  3655.     ,@prefix nvarchar(10)=N'@c' -- prefix
  3656.     ,@suffix nvarchar(10)=NULL  -- suffix
  3657. )
  3658. as
  3659. begin
  3660.     declare @cmd nvarchar(4000)
  3661.             ,@qualname nvarchar(512)
  3662.             ,@column_string nvarchar(4000)
  3663.             ,@var_string nvarchar(4000)
  3664.             ,@colname      sysname
  3665.             ,@ccoltype     sysname
  3666.             ,@this_col     int
  3667.             ,@rc           int
  3668.             ,@num_col      int
  3669.     declare @worktab  table( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  3670.     declare @worktab2 table( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  3671.  
  3672.     --
  3673.     -- initialize
  3674.     --
  3675.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  3676.     --
  3677.     -- prepare the assignments and column list for 
  3678.     -- insert statement  
  3679.     --
  3680.     select @num_col = 0
  3681.     DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  3682.     select colid from syscolumns where id = @objid order by colid asc
  3683.  
  3684.     OPEN hCColid
  3685.     FETCH hCColid INTO @this_col
  3686.     WHILE (@@fetch_status != -1)
  3687.     begin
  3688.         exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
  3689.         if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
  3690.         begin
  3691.             if rtrim(@ccoltype) not like N'timestamp' 
  3692.             begin
  3693.                 select @num_col = @num_col + 1
  3694.                     ,@column_string = quotename(@colname)
  3695.                     ,@var_string = @prefix + cast(@this_col as nvarchar(4))
  3696.                 if (@suffix is not null)
  3697.                     select @var_string = @var_string + @suffix
  3698.                 
  3699.                 if (@num_col > 1)
  3700.                 begin
  3701.                     select @column_string = N', ' + @column_string
  3702.                         ,@var_string = N', ' +@var_string 
  3703.                 end
  3704.                 insert into @worktab(procedure_text) values( @column_string )                
  3705.                 insert into @worktab2(procedure_text) values( @var_string )                
  3706.             end
  3707.         end
  3708.         FETCH hCColid INTO @this_col
  3709.     end
  3710.     CLOSE hCColid
  3711.     DEALLOCATE hCColid
  3712.  
  3713.     if (@num_col > 0)
  3714.     begin
  3715.         if (@identity_insert = 1)
  3716.         begin
  3717.             -- Only to call set if identity is not marked for 'not for repl'
  3718.             -- This is to avoid security failure of 'SET' for PAL users
  3719.             if not exists (select * from syscolumns where id = @objid and
  3720.                 ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
  3721.             begin
  3722.                 select @cmd = N'
  3723.             set identity_insert ' + @qualname + N' on '
  3724.                 insert into #proctext(procedure_text) values( @cmd )
  3725.             end
  3726.         end
  3727.  
  3728.         select @cmd = N'
  3729.             insert into ' + @qualname + N'( '
  3730.         insert into #proctext(procedure_text) values( @cmd )
  3731.         insert into #proctext(procedure_text) 
  3732.             select procedure_text from @worktab order by c1 asc
  3733.         select @cmd = N' )
  3734.             values ( '
  3735.         insert into #proctext(procedure_text) values( @cmd )
  3736.         insert into #proctext(procedure_text) 
  3737.             select procedure_text from @worktab2 order by c1 asc
  3738.         select @cmd = N' )'
  3739.         insert into #proctext(procedure_text) values( @cmd )
  3740.  
  3741.         if (@identity_insert = 1)
  3742.         begin
  3743.             -- Only to call set if identity is not marked for 'not for repl'
  3744.             -- This is to avoid security failure of 'SET' for PAL users
  3745.             if not exists (select * from syscolumns where id = @objid and
  3746.                 ColumnProperty(id, name, 'IsIdNotForRepl') = 1)
  3747.             begin
  3748.                 select @cmd = N'
  3749.             set identity_insert ' + @qualname + N' off '
  3750.                 insert into #proctext(procedure_text) values( @cmd )
  3751.             end
  3752.         end
  3753.     end
  3754.     --
  3755.     -- all done
  3756.     -- 
  3757.     return 0
  3758. end
  3759. go
  3760. exec dbo.sp_MS_marksystemobject sp_script_insertforcftresolution
  3761. go
  3762.  
  3763. --------------------------------------------------------------------------------
  3764. --. sp_MSscriptinsertconflictfinder
  3765. --------------------------------------------------------------------------------
  3766.  
  3767. if exists (select * from sysobjects
  3768.     where type = 'P' and name = 'sp_MSscriptinsertconflictfinder')
  3769. drop procedure sp_MSscriptinsertconflictfinder
  3770. go
  3771. raiserror('Creating procedure sp_MSscriptinsertconflictfinder', 0,1)
  3772. go
  3773. create procedure sp_MSscriptinsertconflictfinder 
  3774. (
  3775.     @publication sysname        -- publication name
  3776.     ,@article sysname            -- article name
  3777.     ,@objid int                -- object id
  3778.     ,@columns binary(32)        -- columns replicated
  3779. )
  3780. as
  3781. begin
  3782.     declare 
  3783.             @rc int
  3784.             ,@cmd nvarchar(4000)
  3785.             ,@artid int
  3786.             ,@pubid int
  3787.             ,@qualname nvarchar(512)
  3788.             ,@fhasnonpkuniquekeys int
  3789.  
  3790.     --
  3791.     -- initialize the vars we will use
  3792.     --
  3793.     select @pubid = pubid 
  3794.     from syspublications 
  3795.     where name = @publication
  3796.     select @artid = artid
  3797.     from sysarticles 
  3798.     where name = @article 
  3799.         and pubid = @pubid
  3800.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  3801.     --
  3802.     --  check if this article has non PK unique keys
  3803.     --
  3804.     exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
  3805.     --
  3806.     -- start scripting
  3807.     --
  3808.     select @cmd = N'
  3809.     
  3810.     '+N'--
  3811.     '+N'-- --------------------------------------------------------------------
  3812.     '+N'-- This is the crux of the proc for conflict resolution 
  3813.     '+N'-- This code block is essentially a state machine
  3814.     '+N'-- where we ascertain the state of resolution
  3815.     '+N'-- The actions of this resolution varies for the policy
  3816.     '+N'-- The comments for each state outline the policy
  3817.     '+N'-- specific actions 
  3818.     '+N'-- --------------------------------------------------------------------
  3819.     '+N'--'
  3820.     insert into #proctext(procedure_text) values( @cmd )
  3821.     --
  3822.     -- continue scripting
  3823.     --
  3824.     select @cmd = N'
  3825.     if (@execution_mode in (@QPubWins, @QSubWins))
  3826.     begin
  3827.         '+N'--
  3828.         '+N'-- initialize the conflict case
  3829.         '+N'--
  3830.         select @cftcase = 0
  3831.  
  3832.         if (@rowcount = 0)
  3833.         begin
  3834.             '+N'--
  3835.             '+N'-- we had conflict for this command
  3836.             '+N'--
  3837.             if (@error in (547, 2601, 2627))
  3838.             begin'
  3839.     insert into #proctext(procedure_text) values( @cmd )
  3840.     select @cmd = N'
  3841.                 '+N'--
  3842.                 '+N'-- Conflict due to unique key/constraint
  3843.                 '+N'--'
  3844.     insert into #proctext(procedure_text) values( @cmd )
  3845.     --
  3846.     -- script row check with PK
  3847.     --
  3848.     select @cmd = N'
  3849.                 if exists (select * from ' + @qualname 
  3850.     insert into #proctext(procedure_text) values( @cmd )
  3851.     exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0
  3852.     insert into #proctext(procedure_text) values( N' )')
  3853.     --
  3854.     -- continue scripting
  3855.     --
  3856.     select @cmd = N'
  3857.                 begin
  3858.                     '+N'--
  3859.                     '+N'-- case 21: A row with same PK already exists
  3860.                     '+N'-- PubWins -----------------------------------------------------------
  3861.                     '+N'-- generate delete compensating action for row with PK
  3862.                     '+N'-- generate delete + insert compensating action with values for all unique keys 
  3863.                     '+N'-- SubWins -----------------------------------------------------------
  3864.                     '+N'-- delete rows with values of all keys
  3865.                     '+N'-- insert row with values
  3866.                     '+N'--
  3867.                     select @cftcase = 21 
  3868.                 end'
  3869.     insert into #proctext(procedure_text) values( @cmd )
  3870.     --
  3871.     -- script this block if the article has non PK unique keys
  3872.     --
  3873.     if (@fhasnonpkuniquekeys = 1)
  3874.     begin
  3875.         select @cmd = N'
  3876.                 else
  3877.                 begin
  3878.                     '+N'--
  3879.                     '+N'-- case 22: A row with same nonPK key(s) already exists
  3880.                     '+N'-- PubWins -----------------------------------------------------------
  3881.                     '+N'-- generate delete compensating action for row with PK
  3882.                     '+N'-- generate delete + insert compensating action with values for non PK keys 
  3883.                     '+N'-- SubWins -----------------------------------------------------------
  3884.                     '+N'-- delete rows with values of non PK keys
  3885.                     '+N'-- insert row with values
  3886.                     '+N'--
  3887.                     select @cftcase = 22 
  3888.                 end'
  3889.         insert into #proctext(procedure_text) values( @cmd )
  3890.     end
  3891.     --
  3892.     -- continue scripting
  3893.     --
  3894.     select @cmd = N'
  3895.             end
  3896.         end
  3897.         else if (@execution_mode = @QPubWins)
  3898.         begin
  3899.             '+N'--
  3900.             '+N'-- we had no conflict for this command
  3901.             '+N'-- We need to process this block only in the Publisher Wins cases
  3902.             '+N'--
  3903.  
  3904.             '+N'--
  3905.             '+N'-- case 23: No conflict
  3906.             '+N'-- PubWins -----------------------------------------------------------
  3907.             '+N'-- generate delete compensating action with PK
  3908.             '+N'-- 
  3909.             select @cftcase = 23
  3910.         end    
  3911.     end'
  3912.     insert into #proctext(procedure_text) values( @cmd )
  3913.     --
  3914.     -- continue scripting
  3915.     --
  3916.     select @cmd = N'
  3917.  
  3918.     '+N'--
  3919.     '+N'-- --------------------------------------------------------------------
  3920.     '+N'-- Now the generation phase
  3921.     '+N'-- Use the conflict case value to decide what to do
  3922.     '+N'-- --------------------------------------------------------------------
  3923.     '+N'--'
  3924.     insert into #proctext(procedure_text) values( @cmd )
  3925.     --
  3926.     -- all done
  3927.     --
  3928.     return 0
  3929. end
  3930. go
  3931. exec dbo.sp_MS_marksystemobject sp_MSscriptinsertconflictfinder
  3932. go
  3933.  
  3934. --------------------------------------------------------------------------------
  3935. --. sp_MSscriptupdateconflictfinder
  3936. --------------------------------------------------------------------------------
  3937.  
  3938. if exists (select * from sysobjects
  3939.     where type = 'P' and name = 'sp_MSscriptupdateconflictfinder')
  3940. drop procedure sp_MSscriptupdateconflictfinder
  3941. go
  3942. raiserror('Creating procedure sp_MSscriptupdateconflictfinder', 0,1)
  3943. go
  3944. create procedure sp_MSscriptupdateconflictfinder 
  3945. (
  3946.     @publication sysname        -- publication name
  3947.     ,@article sysname            -- article name
  3948.     ,@objid int                -- object id
  3949.     ,@columns binary(32)        -- columns replicated
  3950. )
  3951. as
  3952. begin
  3953.     declare 
  3954.             @rc int
  3955.             ,@cmd nvarchar(4000)
  3956.             ,@artid int
  3957.             ,@pubid int
  3958.             ,@qualname nvarchar(512)
  3959.             ,@fhasnonpkuniquekeys int
  3960.  
  3961.     --
  3962.     -- initialize the vars we will use
  3963.     --
  3964.     select @pubid = pubid 
  3965.     from syspublications 
  3966.     where name = @publication
  3967.     select @artid = artid
  3968.     from sysarticles 
  3969.     where name = @article 
  3970.         and pubid = @pubid
  3971.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  3972.     --
  3973.     --  check if this article has non PK unique keys
  3974.     --
  3975.     exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
  3976.     --
  3977.     -- start scripting
  3978.     --
  3979.     select @cmd = N'
  3980.     ' + N'--
  3981.     ' + N'-- --------------------------------------------------------------------
  3982.     ' + N'-- This is the crux of the proc for conflict resolution 
  3983.     ' + N'-- This code block is essentially a state machine
  3984.     ' + N'-- where we ascertain the state of resolution
  3985.     ' + N'-- The actions of this resolution varies for the policy
  3986.     ' + N'-- The comments for each state outline the policy
  3987.     ' + N'-- specific actions (I have only outlined Pub Wins for
  3988.     ' + N'-- now)
  3989.     ' + N'-- --------------------------------------------------------------------
  3990.     ' + N'--'
  3991.     insert into #proctext(procedure_text) values( @cmd )
  3992.     select @cmd = N'
  3993.     if (@execution_mode in (@QPubWins, @QSubWins))
  3994.     begin 
  3995.         declare @fpkeyupdated int'
  3996.     insert into #proctext(procedure_text) values( @cmd )
  3997.     --
  3998.     -- non PK unique keys specific scripting
  3999.     --
  4000.     if (@fhasnonpkuniquekeys = 1)
  4001.     begin
  4002.         select @cmd = N'
  4003.         declare @fnpukeyupdated int'
  4004.         insert into #proctext(procedure_text) values( @cmd )
  4005.     end
  4006.     --
  4007.     -- continue scripting
  4008.     --
  4009.     select @cmd = N'
  4010.         ' + N'--
  4011.         ' + N'-- initialize the conflict case
  4012.         ' + N'--
  4013.         select @cftcase = 0 '
  4014.     insert into #proctext(procedure_text) values( @cmd )
  4015.     --
  4016.     -- script the PK update check
  4017.     --
  4018.     select @cmd = N'
  4019.         exec @fpkeyupdated = dbo.sp_MSispkupdateinconflict ' + 
  4020.         cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap'
  4021.     insert into #proctext(procedure_text) values( @cmd )
  4022.     select @cmd = N'
  4023.         if (@fpkeyupdated = -1)
  4024.             return -1'
  4025.     insert into #proctext(procedure_text) values( @cmd )
  4026.     --
  4027.     -- script non PK unique key update check
  4028.     --
  4029.     if (@fhasnonpkuniquekeys = 1)
  4030.     begin
  4031.         select @cmd = N'
  4032.         exec @fnpukeyupdated = dbo.sp_MSisnonpkukupdateinconflict ' + 
  4033.         cast(@pubid as nvarchar(10)) + N', ' + cast(@artid as nvarchar(10)) + N', @bitmap'
  4034.         insert into #proctext(procedure_text) values( @cmd )
  4035.         select @cmd = N'
  4036.         if (@fnpukeyupdated = -1)
  4037.             return -1'
  4038.         insert into #proctext(procedure_text) values( @cmd )
  4039.     end
  4040.     --
  4041.     -- continue scripting
  4042.     --
  4043.     select @cmd = N'
  4044.         if (@rowcount = 0)
  4045.         begin
  4046.             ' + N'--
  4047.             ' + N'-- we had conflict for this command
  4048.             ' + N'--'
  4049.     insert into #proctext(procedure_text) values( @cmd )
  4050.     if (@fhasnonpkuniquekeys = 1)
  4051.     begin
  4052.         select @cmd = N'
  4053.             if (@error in (547, 2601, 2627) or (@fpkeyupdated = 1) or (@fnpukeyupdated = 1)) '
  4054.     end
  4055.     else
  4056.     begin
  4057.         select @cmd = N'
  4058.             if (@error in (547, 2601, 2627) or (@fpkeyupdated = 1)) '
  4059.     end
  4060.     insert into #proctext(procedure_text) values( @cmd )
  4061.     --
  4062.     -- continue scripting
  4063.     --
  4064.     select @cmd = N'
  4065.             begin
  4066.                 ' + N'--
  4067.                 ' + N'-- Conflict due to unique key/constraint
  4068.                 ' + N'--'
  4069.     insert into #proctext(procedure_text) values( @cmd )
  4070.     select @cmd = N'
  4071.                 if (@fpkeyupdated = 1)
  4072.                 begin
  4073.                     ' + N'--
  4074.                     ' + N'-- PK is being updated 
  4075.                     ' + N'--'
  4076.     insert into #proctext(procedure_text) values( @cmd )
  4077.     --
  4078.     -- script check for rows with all keys with OLD values
  4079.     --
  4080.     --if (row exists with pk = OLD_PK or non PK unique keys = OLD values)
  4081.     select @cmd = N'
  4082.                     if exists (select * from ' + @qualname 
  4083.     insert into #proctext(procedure_text) values( @cmd )
  4084.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  4085.                 ,@columns = @columns
  4086.                 ,@prefix = N'@c' 
  4087.                 ,@suffix = N'_old'
  4088.                 ,@mode = 6
  4089.     insert into #proctext(procedure_text) values( N' )')
  4090.     --
  4091.     -- continue scripting
  4092.     --
  4093.     select @cmd = N'
  4094.                     begin
  4095.                         ' + N'--
  4096.                         ' + N'-- case 14: row(s) with OLD key values exist(s) 
  4097.                         ' + N'-- (and rows with NEW key values do not exist)
  4098.                         ' + N'-- PubWins -----------------------------------------------------------
  4099.                         ' + N'-- generate delete + insert compensating action with OLD values for all unique keys 
  4100.                         ' + N'-- generate delete compensating action for row with PK = NEW_PK 
  4101.                         ' + N'-- SubWins -----------------------------------------------------------
  4102.                         ' + N'-- delete row with PK=OLD_PK
  4103.                         ' + N'-- insert row with NEW values (use bitmap)
  4104.                         ' + N'--
  4105.                         select @cftcase = 14
  4106.                     end'
  4107.     insert into #proctext(procedure_text) values( @cmd )
  4108.     --
  4109.     -- script check for rows with all keys with NEW values (use bitmap)
  4110.     --
  4111.     --if (row exists with pk = NEW_PK or non PK unique keys = NEW values)
  4112.     select @cmd = N'
  4113.                     if exists (select * from ' + @qualname 
  4114.     insert into #proctext(procedure_text) values( @cmd )
  4115.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  4116.                 ,@columns = @columns
  4117.                 ,@prefix = N'@c' 
  4118.                 ,@suffix = NULL
  4119.                 ,@mode = 6
  4120.     insert into #proctext(procedure_text) values( N' )')
  4121.     --
  4122.     -- continue scripting
  4123.     --
  4124.     select @cmd = N'
  4125.                     begin
  4126.                         ' + N'--
  4127.                         ' + N'-- row with NEW key values exist(s)
  4128.                         ' + N'--
  4129.                         if (@cftcase = 14)
  4130.                         begin
  4131.                             ' + N'--
  4132.                             ' + N'-- case 15: rows exist with NEW key values and OLD key values
  4133.                             ' + N'-- PubWins -----------------------------------------------------------
  4134.                             ' + N'-- generate delete + insert compensating action with OLD values for all unique keys 
  4135.                             ' + N'-- generate delete + insert compensating action with NEW values for all unique keys 
  4136.                             ' + N'-- SubWins -----------------------------------------------------------
  4137.                             ' + N'-- delete row with PK=OLD_PK
  4138.                             ' + N'-- delete rows with NEW values of all keys
  4139.                             ' + N'-- insert row with NEW values (use bitmap)
  4140.                             ' + N'--
  4141.                             select @cftcase = 15 
  4142.                         end'
  4143.     insert into #proctext(procedure_text) values( @cmd )
  4144.     select @cmd = N'
  4145.                         else
  4146.                         begin
  4147.                             ' + N'--
  4148.                             ' + N'-- case 16: rows exist with NEW key values and 
  4149.                             ' + N'-- row does not exist for OLD values
  4150.                             ' + N'-- PubWins -----------------------------------------------------------
  4151.                             ' + N'-- generate delete compensating action for row with PK = OLD_PK 
  4152.                             ' + N'-- generate delete + insert compensating action with NEW values for all unique keys 
  4153.                             ' + N'-- SubWins -----------------------------------------------------------
  4154.                             ' + N'-- delete rows with NEW values of all keys
  4155.                             ' + N'-- insert row with NEW values (use bitmap)
  4156.                             ' + N'--
  4157.                             select @cftcase = 16 
  4158.                         end
  4159.                     end'
  4160.     insert into #proctext(procedure_text) values( @cmd )
  4161.     select @cmd = N'
  4162.                     else
  4163.                     begin
  4164.                         ' + N'--
  4165.                         ' + N'-- row with NEW key values does not exist
  4166.                         ' + N'--
  4167.                         if (@cftcase = 0)
  4168.                         begin
  4169.                             ' + N'--
  4170.                             ' + N'-- case 12 : no existing rows with OLD key values or NEW or new key values
  4171.                             ' + N'-- PubWins -----------------------------------------------------------
  4172.                             ' + N'-- generate delete compensating action with PK = OLD_PK
  4173.                             ' + N'-- generate delete compensating action with PK = NEW_PK
  4174.                             ' + N'-- SubWins -----------------------------------------------------------
  4175.                             ' + N'-- insert row with NEW values (use bitmap)
  4176.                             ' + N'--
  4177.                             select @cftcase = 12 
  4178.                         end'
  4179.     insert into #proctext(procedure_text) values( @cmd )
  4180.     select @cmd = N'
  4181.                         else
  4182.                         begin
  4183.                             ' + N'--
  4184.                             ' + N'-- case 14: row(s) with OLD key values exist(s) 
  4185.                             ' + N'-- (and rows with NEW key values do not exist)
  4186.                             ' + N'-- PubWins -----------------------------------------------------------
  4187.                             ' + N'-- generate delete + insert compensating action with OLD values for all unique keys 
  4188.                             ' + N'-- generate delete compensating action for row with PK = NEW_PK 
  4189.                             ' + N'-- SubWins -----------------------------------------------------------
  4190.                             ' + N'-- delete row with PK=OLD_PK
  4191.                             ' + N'-- insert row with NEW values (use bitmap)
  4192.                             ' + N'--
  4193.                             select @cftcase = 14
  4194.                         end
  4195.                     end
  4196.                 end'
  4197.     insert into #proctext(procedure_text) values( @cmd )
  4198.     --
  4199.     -- script this block if the article has non PK unique keys
  4200.     --
  4201.     if (@fhasnonpkuniquekeys = 1)
  4202.     begin
  4203.         --
  4204.         -- continue scripting
  4205.         --
  4206.         select @cmd = N'
  4207.                 else if (@fnpukeyupdated = 1)
  4208.                 begin
  4209.                     '+N'-- 
  4210.                     '+N'-- non PK unique keys are being updated but PK is not updated
  4211.                     '+N'-- OLD_PK == NEW_PK in these cases
  4212.                     '+N'--'
  4213.         insert into #proctext(procedure_text) values( @cmd )
  4214.         --
  4215.         -- script the pkrowexists assignment
  4216.         --
  4217.         select @cmd = N'
  4218.                     declare @pkrowexist bit
  4219.                     
  4220.                     if exists (select * from ' + @qualname 
  4221.         insert into #proctext(procedure_text) values( @cmd )
  4222.         exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
  4223.         select @cmd =  N' )
  4224.                         select @pkrowexist = 1 '
  4225.         insert into #proctext(procedure_text) values( @cmd )
  4226.         --
  4227.         -- script check for rows with non PK keys with OLD values
  4228.         --
  4229.         -- if (rows exist with OLD values of non PK unique keys values)
  4230.         select @cmd = N'
  4231.                     if exists (select * from ' + @qualname 
  4232.         insert into #proctext(procedure_text) values( @cmd )
  4233.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  4234.                     ,@columns = @columns
  4235.                     ,@prefix = N'@c' 
  4236.                     ,@suffix = N'_old'
  4237.                     ,@mode = 7
  4238.         insert into #proctext(procedure_text) values( N' )')
  4239.         --
  4240.         -- continue scripting
  4241.         --
  4242.         select @cmd = N'
  4243.                     begin
  4244.                         if (@pkrowexist = 1)
  4245.                         begin
  4246.                             '+N'--
  4247.                             '+N'-- case 10: rows exist with OLD non PK key values
  4248.                             '+N'-- (and rows with NEW non PK key values do not exist)
  4249.                             '+N'-- and row with OLD_PK exists
  4250.                             '+N'-- PubWins -----------------------------------------------------------
  4251.                             '+N'-- generate delete + insert compensation action with OLD values for all keys 
  4252.                             '+N'-- generate delete compensating action with NEW values for non PK keys
  4253.                             '+N'-- SubWins -----------------------------------------------------------
  4254.                             '+N'-- delete row with PK=OLD_PK
  4255.                             '+N'-- insert row with NEW values (use bitmap)
  4256.                             '+N'--
  4257.                             select @cftcase = 10
  4258.                         end'
  4259.         insert into #proctext(procedure_text) values( @cmd )
  4260.         select @cmd = N'
  4261.                         else
  4262.                         begin
  4263.                             '+N'--
  4264.                             '+N'-- case 21: rows exist with OLD non PK key values
  4265.                             '+N'-- (and rows with NEW non PK key values do not exist)
  4266.                             '+N'-- and row with OLD_PK does not exist
  4267.                             '+N'-- PubWins -----------------------------------------------------------
  4268.                             '+N'-- generate delete with PK = OLD_PK
  4269.                             '+N'-- generate delete + insert compensation action with OLD values for non PK keys 
  4270.                             '+N'-- generate delete compensating action with NEW values for non PK keys
  4271.                             '+N'-- SubWins -----------------------------------------------------------
  4272.                             '+N'-- delete row with PK=OLD_PK
  4273.                             '+N'-- insert row with NEW values (use bitmap)
  4274.                             '+N'--
  4275.                             select @cftcase = 21
  4276.                         end
  4277.                     end '
  4278.         insert into #proctext(procedure_text) values( @cmd )
  4279.         --
  4280.         -- script check for rows with non PK keys with NEW values (use bitmap)
  4281.         --
  4282.         -- if (rows exist with NEW values of non PK unique keys values)
  4283.         select @cmd = N'
  4284.                     if exists (select * from ' + @qualname 
  4285.         insert into #proctext(procedure_text) values( @cmd )
  4286.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  4287.                     ,@columns = @columns
  4288.                     ,@prefix = N'@c' 
  4289.                     ,@suffix = NULL
  4290.                     ,@mode = 7
  4291.         insert into #proctext(procedure_text) values( N' )')
  4292.         --
  4293.         -- continue scripting
  4294.         --
  4295.         select @cmd = N'
  4296.                     begin
  4297.                         '+N'--
  4298.                         '+N'-- find the type of conflict
  4299.                         '+N'--
  4300.                         if (@cftcase in (10,21))
  4301.                         begin
  4302.                             if (@pkrowexist = 1)
  4303.                             begin
  4304.                                 '+N'--
  4305.                                 '+N'-- case 20: rows exist with OLD and NEW values of non PK keys
  4306.                                 '+N'-- and row with OLD_PK exists
  4307.                                 '+N'-- PubWins -----------------------------------------------------------
  4308.                                 '+N'-- generate delete + insert compensation action with OLD values for all keys 
  4309.                                 '+N'-- generate delete + insert compensation action with NEW values for non PK keys 
  4310.                                 '+N'-- SubWins -----------------------------------------------------------
  4311.                                 '+N'-- delete row with PK=OLD_PK
  4312.                                 '+N'-- delete row with NEW values for non PK keys
  4313.                                 '+N'-- insert row with NEW values (use bitmap)
  4314.                                 '+N'--
  4315.                                 select @cftcase = 20 
  4316.                             end '
  4317.         insert into #proctext(procedure_text) values( @cmd )
  4318.         select @cmd = N'
  4319.                             else
  4320.                             begin
  4321.                                 '+N'--
  4322.                                 '+N'-- case 22: rows exist with OLD and NEW values of non PK keys
  4323.                                 '+N'-- and row with OLD_PK does not exist
  4324.                                 '+N'-- PubWins -----------------------------------------------------------
  4325.                                 '+N'-- generate delete with PK = OLD_PK
  4326.                                 '+N'-- generate delete + insert compensation action with OLD values for non PK keys 
  4327.                                 '+N'-- generate delete + insert compensation action with NEW values for non PK keys 
  4328.                                 '+N'-- SubWins -----------------------------------------------------------
  4329.                                 '+N'-- delete row with PK=OLD_PK
  4330.                                 '+N'-- delete row with NEW values for non PK keys
  4331.                                 '+N'-- insert row with NEW values (use bitmap)
  4332.                                 '+N'--
  4333.                                 select @cftcase = 22 
  4334.                             end
  4335.                         end '
  4336.         insert into #proctext(procedure_text) values( @cmd )
  4337.         select @cmd = N'
  4338.                         else
  4339.                         begin
  4340.                             if (@pkrowexist = 1)
  4341.                             begin
  4342.                                 '+N'--
  4343.                                 '+N'-- case 17: rows exist with NEW values of non PK keys  
  4344.                                 '+N'-- and row does not exist with OLD values of non PK keys
  4345.                                 '+N'-- and row with OLD_PK exists
  4346.                                 '+N'-- PubWins -----------------------------------------------------------
  4347.                                 '+N'-- generate delete compensating action with OLD values for non PK keys 
  4348.                                 '+N'-- generate delete + insert compensation action with NEW values for all keys 
  4349.                                 '+N'-- SubWins -----------------------------------------------------------
  4350.                                 '+N'-- delete row with NEW values for non PK keys
  4351.                                 '+N'-- insert row with NEW values (use bitmap)
  4352.                                 '+N'--
  4353.                                 select @cftcase = 17 
  4354.                             end '
  4355.         insert into #proctext(procedure_text) values( @cmd )
  4356.         select @cmd = N'
  4357.                             else
  4358.                             begin
  4359.                                 '+N'--
  4360.                                 '+N'-- case 23: rows exist with NEW values of non PK keys  
  4361.                                 '+N'-- and row does not exist with OLD values of non PK keys
  4362.                                 '+N'-- and row with OLD_PK does not exist
  4363.                                 '+N'-- PubWins -----------------------------------------------------------
  4364.                                 '+N'-- delete row with PK=OLD_PK
  4365.                                 '+N'-- generate delete compensating action with OLD values for non PK keys 
  4366.                                 '+N'-- generate delete + insert compensation action with NEW values for non PK keys 
  4367.                                 '+N'-- SubWins -----------------------------------------------------------
  4368.                                 '+N'-- delete row with NEW values for non PK keys
  4369.                                 '+N'-- insert row with NEW values (use bitmap)
  4370.                                 '+N'--
  4371.                                 select @cftcase = 23 
  4372.                             end
  4373.                         end
  4374.                     end '
  4375.         insert into #proctext(procedure_text) values( @cmd )
  4376.         select @cmd = N'
  4377.                     else
  4378.                     begin
  4379.                         '+N'--
  4380.                         '+N'-- row does not exist with NEW values of non PK keys
  4381.                         '+N'--
  4382.                         if (@cftcase = 0)
  4383.                         begin
  4384.                             if (@pkrowexist = 1)
  4385.                             begin
  4386.                                 '+N'--
  4387.                                 '+N'-- case 18 : no existing rows with OLD or NEW values of non PK keys
  4388.                                 '+N'-- and row with OLD_PK exists
  4389.                                 '+N'-- PubWins -----------------------------------------------------------
  4390.                                 '+N'-- delete row with PK=OLD_PK
  4391.                                 '+N'-- generate delete compensating action with OLD values for non PK keys 
  4392.                                 '+N'-- generate delete compensating action with NEW values for non PK keys 
  4393.                                 '+N'-- generate insert with PK = OLD_PK
  4394.                                 '+N'-- SubWins -----------------------------------------------------------
  4395.                                 '+N'-- insert row with NEW values (use bitmap)
  4396.                                 '+N'--
  4397.                                 select @cftcase = 18 
  4398.                             end '
  4399.         insert into #proctext(procedure_text) values( @cmd )
  4400.         select @cmd = N'
  4401.                             else
  4402.                             begin
  4403.                                 '+N'--
  4404.                                 '+N'-- case 24 : no existing rows with OLD or NEW values of non PK keys
  4405.                                 '+N'-- and row with OLD_PK does not exist
  4406.                                 '+N'-- PubWins -----------------------------------------------------------
  4407.                                 '+N'-- delete row with PK=OLD_PK
  4408.                                 '+N'-- generate delete compensating action with OLD values for non PK keys 
  4409.                                 '+N'-- generate delete compensating action with NEW values for non PK keys 
  4410.                                 '+N'-- SubWins -----------------------------------------------------------
  4411.                                 '+N'-- insert row with NEW values (use bitmap)
  4412.                                 '+N'--
  4413.                                 select @cftcase = 24 
  4414.                             end
  4415.                         end
  4416.                     end
  4417.                 end '
  4418.         insert into #proctext(procedure_text) values( @cmd )
  4419.     end
  4420.     --
  4421.     -- continue scripting
  4422.     --
  4423.     select @cmd = N'
  4424.             end
  4425.             else
  4426.             begin
  4427.                 ' + N'--
  4428.                 ' + N'-- Conflict due non key column change or row deleted
  4429.                 ' + N'--'
  4430.     insert into #proctext(procedure_text) values( @cmd )
  4431.     --
  4432.     -- script check for rows with pk = OLD_PK
  4433.     --
  4434.     select @cmd = N'
  4435.                 if exists (select * from ' + @qualname 
  4436.     insert into #proctext(procedure_text) values( @cmd )
  4437.     exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
  4438.     insert into #proctext(procedure_text) values( N' )')
  4439.     --
  4440.     -- continue scripting
  4441.     --
  4442.     select @cmd = N'
  4443.                 begin
  4444.                     ' + N'--
  4445.                     ' + N'-- case 11: row exists
  4446.                     ' + N'-- PubWins -----------------------------------------------------------
  4447.                     ' + N'-- generate delete + insert compensating action with PK = OLD_PK
  4448.                     ' + N'-- SubWins -----------------------------------------------------------
  4449.                     ' + N'-- delete row with PK=OLD_PK
  4450.                     ' + N'-- insert row with NEW values (use bitmap)
  4451.                     ' + N'--
  4452.                     select @cftcase = 11
  4453.                 end'
  4454.     insert into #proctext(procedure_text) values( @cmd )
  4455.     select @cmd = N'
  4456.                 else
  4457.                 begin
  4458.                     ' + N'--
  4459.                     ' + N'-- case 13: row does not exist
  4460.                     ' + N'-- PubWins -----------------------------------------------------------
  4461.                     ' + N'-- generate delete compensating action with PK = OLD_PK
  4462.                     ' + N'-- SubWins -----------------------------------------------------------
  4463.                     ' + N'-- insert row with NEW values (use bitmap)
  4464.                     ' + N'--
  4465.                     select @cftcase = 13
  4466.                 end
  4467.             end
  4468.         end'
  4469.     insert into #proctext(procedure_text) values( @cmd )
  4470.     select @cmd = N'
  4471.         else if (@execution_mode = @QPubWins)
  4472.         begin
  4473.             ' + N'--
  4474.             ' + N'-- we had no conflict for this command
  4475.             ' + N'-- We need to process this block only in the Publisher Wins cases
  4476.             ' + N'--'
  4477.     insert into #proctext(procedure_text) values( @cmd )
  4478.     select @cmd = N'
  4479.             if (@fpkeyupdated = 1)
  4480.             begin
  4481.                 ' + N'--
  4482.                 ' + N'-- PK is being updated
  4483.                 ' + N'-- PubWins -----------------------------------------------------------
  4484.                 ' + N'-- generate delete + insert compensating action with OLD values for all unique keys 
  4485.                 ' + N'-- generate delete compensating action with PK=NEW_PK
  4486.                 ' + N'-- 
  4487.                 select @cftcase = 1
  4488.             end'
  4489.     insert into #proctext(procedure_text) values( @cmd )
  4490.     select @cmd = N'
  4491.             else
  4492.             begin
  4493.                 ' + N'--
  4494.                 ' + N'-- non PK column updated
  4495.                 ' + N'-- PubWins -----------------------------------------------------------
  4496.                 ' + N'-- generate delete + insert compensating action with OLD values for all unique keys
  4497.                 ' + N'--
  4498.                 select @cftcase = 3
  4499.             end
  4500.         end
  4501.     end'
  4502.     insert into #proctext(procedure_text) values( @cmd )
  4503.     --
  4504.     -- all done
  4505.     --
  4506.     return 0    
  4507. end
  4508. go
  4509. exec dbo.sp_MS_marksystemobject sp_MSscriptupdateconflictfinder
  4510. go
  4511.  
  4512. --------------------------------------------------------------------------------
  4513. --. sp_MSscript_update_statement
  4514. --------------------------------------------------------------------------------
  4515.  
  4516. if exists (select * from sysobjects
  4517.     where type = 'P' and name = 'sp_MSscript_update_statement')
  4518. drop procedure sp_MSscript_update_statement
  4519. go
  4520. raiserror('Creating procedure sp_MSscript_update_statement', 0,1)
  4521. go
  4522. create procedure sp_MSscript_update_statement (
  4523.     @publication sysname,
  4524.     @article     sysname, 
  4525.     @objid int,
  4526.     @columns binary(32),
  4527.     @queued_pub bit = 0
  4528. )
  4529. as
  4530. BEGIN
  4531.     declare @cmd            nvarchar(4000)
  4532.             ,@cmd2            nvarchar(4000)
  4533.             ,@qualname        nvarchar(512)
  4534.             ,@colname        sysname
  4535.             ,@typestring    nvarchar(4000)
  4536.             ,@spacer        nvarchar(1)
  4537.             ,@ccoltype        sysname
  4538.             ,@this_col        int
  4539.             ,@rc            int
  4540.             ,@column        nvarchar(4000)
  4541.             ,@num_col        int
  4542.             ,@bitstr nvarchar(20)
  4543.             ,@bytestr nvarchar(20)
  4544.             ,@art_col        int -- position in the article partition.
  4545.             ,@isset            int
  4546.             ,@timestamp_subscribed bit
  4547.             ,@pubid            int
  4548.  
  4549.     select @pubid = pubid from syspublications where name = @publication
  4550.  
  4551.     if exists (select * from sysarticles where pubid = @pubid and
  4552.         name = @article and
  4553.         status & 32 <> 0)
  4554.         select @timestamp_subscribed = 1
  4555.     else
  4556.         select @timestamp_subscribed = 0
  4557.     
  4558.     --
  4559.     -- Start scripting
  4560.     --
  4561.     select @cmd = N'
  4562.     ' + N'--
  4563.     ' + N'-- detection/conflict resolution stage
  4564.     ' + N'--'
  4565.     
  4566.     if (@queued_pub = 1)
  4567.     begin
  4568.         select @cmd = @cmd + N'
  4569.     if (@execution_mode = @QPubWins)
  4570.         save tran cftpass
  4571.     '
  4572.     end
  4573.     insert into #proctext(procedure_text) values(@cmd)
  4574.     
  4575.     --
  4576.     -- Generate the update statement
  4577.     --
  4578.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  4579.     select @cmd2 = N'
  4580.     update ' + @qualname + N' set
  4581.     '
  4582.  
  4583.     select @spacer = N' 
  4584.         '
  4585.     select @cmd = N''
  4586.     exec dbo.sp_MSpad_command @cmd output, 8
  4587.     
  4588.     select @num_col = 0
  4589.     select @art_col = 0
  4590.  
  4591.     DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  4592.     select colid from syscolumns where id = @objid order by colid asc
  4593.  
  4594.     OPEN hCColid
  4595.     FETCH hCColid INTO @this_col
  4596.     WHILE (@@fetch_status <> -1)
  4597.     begin
  4598.         -- Get the ordinal of the article partition or not.
  4599.         exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
  4600.         if @isset = 0
  4601.         begin
  4602.             -- Special handling of a timestamp col in a queued tran publication
  4603.             -- See sp_helparticlecolumns : xtype 189 is timestamp
  4604.             if ((@timestamp_subscribed = 1) and 
  4605.                     exists ( select * from dbo.syscolumns where id = @objid and colid = @this_col and xtype = 189))
  4606.                 select @art_col = @art_col + 1
  4607.         end
  4608.         else
  4609.             select @art_col = @art_col + 1
  4610.  
  4611.         exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
  4612.         if @rc = 0 and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
  4613.         begin
  4614.             if rtrim(@ccoltype) not like N'timestamp' and ColumnProperty(@objid, @colname, 'IsIdentity') != 1
  4615.             begin
  4616.                 if @cmd2 is not null
  4617.                 begin
  4618.                     exec dbo.sp_MSflush_command @cmd2 output, 1, 8
  4619.                     select @cmd2 = null
  4620.                 end
  4621.  
  4622.                 select @num_col = @num_col + 1
  4623.                 -- Optimization:
  4624.                 -- Get null or actual column name
  4625.                 -- Note: the output is quoted.
  4626.                 exec dbo.sp_MSget_synctran_column 
  4627.                     @ts_col = null,
  4628.                     @op_type = null , -- 'ins, 'upd', 'del'
  4629.                     @is_new = null,
  4630.                     @primary_key_bitmap = null,
  4631.                     @colname = @colname,
  4632.                     @this_col = @this_col,
  4633.                     @column = @column output,
  4634.                     @from_proc = 1,
  4635.                     @art_col = @art_col -- position in the partition.
  4636.  
  4637.                 select @cmd = @cmd + @spacer + QUOTENAME(@colname) + N' = ' + @column                 
  4638.                 select @spacer = N','
  4639.  
  4640.                 --
  4641.                 -- flush command if necessary
  4642.                 --
  4643.                 exec dbo.sp_MSflush_command @cmd output, 1, 8
  4644.             end
  4645.         end
  4646.         FETCH hCColid INTO @this_col
  4647.     end
  4648.     CLOSE hCColid
  4649.     DEALLOCATE hCColid
  4650.  
  4651.     -- save off cmd fragment
  4652.     if @num_col > 0
  4653.     begin
  4654.         --
  4655.         -- Add the where clause based on the update mode
  4656.         --
  4657.         select @colname = 'msrepl_tran_version'
  4658.         exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', @colname, 4
  4659.     end 
  4660.     else
  4661.     -- set the @@rowcount
  4662.         insert into #proctext(procedure_text) values( N' select @retcode = @retcode
  4663.     ')
  4664.  
  4665.     --
  4666.     -- continue with rest of scripting
  4667.     --
  4668.     select @cmd = N'
  4669.     select @rowcount = @@ROWCOUNT, @error = @@ERROR
  4670.     '
  4671.  
  4672.     if (@queued_pub = 1)
  4673.     begin
  4674.         select @cmd = @cmd + N'
  4675.     if (@execution_mode = @QPubWins)
  4676.         rollback tran cftpass'
  4677.     end
  4678.     insert into #proctext(procedure_text) values(@cmd)
  4679.     --
  4680.     -- Queued specific case
  4681.     --
  4682.     if (@queued_pub = 1)
  4683.     begin
  4684.         --
  4685.         -- script the assignment of new values based on bitmask
  4686.         --
  4687.         select @num_col = 0
  4688.                 ,@art_col = 0
  4689.                 ,@cmd = N'
  4690.     ' + N'--
  4691.     ' + N'-- for conflict resolution - assign the NEW values based on bitmap
  4692.     ' + N'--
  4693.     if (@execution_mode in (@QPubWins, @QSubWins))
  4694.     begin     
  4695.         select '
  4696.         insert into #proctext(procedure_text) values(@cmd)    
  4697.  
  4698.         DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  4699.             select colid from dbo.syscolumns where id = @objid order by colid asc
  4700.  
  4701.         OPEN hCColid
  4702.         FETCH hCColid INTO @this_col
  4703.         WHILE (@@fetch_status != -1)
  4704.         begin
  4705.             -- Get the ordinal of the article partition or not.
  4706.             exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
  4707.             if @isset = 0
  4708.             begin
  4709.                 if ((@timestamp_subscribed = 1) and 
  4710.                         exists ( select * from dbo.syscolumns where id = @objid and colid = @this_col and xtype = 189))
  4711.                     select @art_col = @art_col + 1
  4712.             end
  4713.             else
  4714.                 select @art_col = @art_col + 1
  4715.  
  4716.             exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
  4717.             if ((@rc = 0) 
  4718.                 and EXISTS (select name from dbo.syscolumns where id=@objid and colid=@this_col and iscomputed != 1) 
  4719.                 and (rtrim(@ccoltype) != N'timestamp'))
  4720.             begin
  4721.                 select @num_col = @num_col + 1
  4722.                         ,@bytestr = cast((1 + (@art_col-1) / 8 ) as nvarchar)
  4723.                         ,@bitstr =  cast( power(2, (@art_col-1) % 8 ) as nvarchar)
  4724.  
  4725.                 select @cmd = N'@c' + cast(@this_col as nvarchar(10)) + N' = case substring(@bitmap,' + 
  4726.                     @bytestr + N',1) & ' + @bitstr + N' when ' + @bitstr + 
  4727.                     N' then @c' + cast(@this_col as nvarchar(4)) + 
  4728.                     N' else @c' + cast(@this_col as nvarchar(4)) + N'_old end '
  4729.  
  4730.                 if (@num_col = 1)
  4731.                 begin
  4732.                     select @cmd = N'
  4733.                 ' + @cmd
  4734.                 end
  4735.                 else
  4736.                 begin
  4737.                     select @cmd = N'
  4738.                 , ' + @cmd
  4739.                 end
  4740.                 insert into #proctext(procedure_text) values(@cmd)    
  4741.             end
  4742.             --
  4743.             -- fetch next row
  4744.             --
  4745.             FETCH hCColid INTO @this_col
  4746.         end
  4747.         CLOSE hCColid
  4748.         DEALLOCATE hCColid
  4749.         --
  4750.         -- continue with scripting
  4751.         --
  4752.         select @cmd = N'
  4753.     end'     
  4754.         insert into #proctext(procedure_text) values(@cmd)    
  4755.     end
  4756.     --
  4757.     -- all done
  4758.     --
  4759.     return 0
  4760. END
  4761. go
  4762. exec dbo.sp_MS_marksystemobject sp_MSscript_update_statement
  4763. GO
  4764.  
  4765. --------------------------------------------------------------------------------
  4766. --. sp_MSscript_insert_subwins
  4767. --------------------------------------------------------------------------------
  4768.  
  4769. if exists (select * from sysobjects
  4770.     where type = 'P' and name = 'sp_MSscript_insert_subwins')
  4771. drop procedure sp_MSscript_insert_subwins
  4772. go
  4773. raiserror('Creating procedure sp_MSscript_insert_subwins', 0,1)
  4774. go
  4775. create procedure sp_MSscript_insert_subwins 
  4776. (
  4777.     @publication sysname        -- publication name
  4778.     ,@article sysname            -- article name
  4779.     ,@objid int                -- object id
  4780.     ,@columns binary(32)        -- columns replicated
  4781.     ,@identity_insert bit        -- enable identity insert
  4782. )
  4783. as
  4784. begin
  4785.     declare @cmd nvarchar(4000)
  4786.             ,@qualname nvarchar(512)
  4787.             ,@rc           int
  4788.             ,@fhasnonpkuniquekeys int
  4789.  
  4790.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  4791.     --
  4792.     --  check if this article has non PK unique keys
  4793.     --
  4794.     exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
  4795.     --
  4796.     -- start scripting
  4797.     --
  4798.     select @cmd = N'
  4799.     if (@execution_mode = @QSubWins)
  4800.     begin
  4801.         '+N'--
  4802.         '+N'-- Subscriber wins resolution
  4803.         '+N'-- '
  4804.     insert into #proctext(procedure_text) values( @cmd )
  4805.     --
  4806.     -- script this block if the article has non PK unique keys
  4807.     --
  4808.     if (@fhasnonpkuniquekeys = 1)
  4809.     begin
  4810.         select @cmd = N'
  4811.         if (@cftcase = 22)
  4812.         begin
  4813.             '+N'--
  4814.             '+N'-- delete rows with values of non PK keys
  4815.             '+N'-- '
  4816.         insert into #proctext(procedure_text) values( @cmd )
  4817.         --
  4818.         -- script delete rows with values for non PK keys
  4819.         --
  4820.         select @cmd = N'
  4821.             delete ' + @qualname 
  4822.         insert into #proctext(procedure_text) values( @cmd )
  4823.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  4824.                     ,@columns = @columns
  4825.                     ,@prefix = N'@c' 
  4826.                     ,@suffix = NULL
  4827.                     ,@mode = 7
  4828.         --
  4829.         -- continue scripting
  4830.         --
  4831.         select @cmd = N'
  4832.         end'
  4833.         insert into #proctext(procedure_text) values( @cmd )
  4834.     end
  4835.     --
  4836.     -- continue scripting
  4837.     --
  4838.     select @cmd = N'
  4839.         if (@cftcase = 21)
  4840.         begin
  4841.             '+N'--
  4842.             '+N'-- delete rows with values of all keys
  4843.             '+N'-- '
  4844.     insert into #proctext(procedure_text) values( @cmd )
  4845.     --
  4846.     -- script delete rows with values of all keys 
  4847.     --
  4848.     select @cmd = N'
  4849.             delete ' + @qualname 
  4850.     insert into #proctext(procedure_text) values( @cmd )
  4851.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  4852.                 ,@columns = @columns
  4853.                 ,@prefix = N'@c' 
  4854.                 ,@suffix = NULL
  4855.                 ,@mode = 6
  4856.     --
  4857.     -- continue scripting
  4858.     --
  4859.     select @cmd = N'
  4860.         end
  4861.         if (@cftcase in (21,22))
  4862.         begin
  4863.             '+N'--
  4864.             '+N'-- insert row
  4865.             '+N'-- '
  4866.     insert into #proctext(procedure_text) values( @cmd )
  4867.     --
  4868.     -- script insert row  
  4869.     --
  4870.     exec @rc = sp_script_insertforcftresolution 
  4871.             @objid = @objid
  4872.             ,@columns = @columns
  4873.             ,@identity_insert = @identity_insert
  4874.             ,@prefix = N'@c'
  4875.             ,@suffix = NULL
  4876.     --
  4877.     -- continue scripting
  4878.     --
  4879.     select @cmd = N'
  4880.         end
  4881.  
  4882.         '+N'--
  4883.         '+N'-- --------------------------------------------------------------------
  4884.         '+N'-- all done for conflict resolution for Subscriber Wins policy
  4885.         '+N'-- --------------------------------------------------------------------
  4886.         '+N'--
  4887.     end'
  4888.     insert into #proctext(procedure_text) values( @cmd )
  4889.     --
  4890.     -- all done
  4891.     --
  4892.     return 0
  4893. end
  4894. go
  4895. exec dbo.sp_MS_marksystemobject sp_MSscript_insert_subwins
  4896. go
  4897.  
  4898. --------------------------------------------------------------------------------
  4899. --. sp_MSscript_insert_pubwins
  4900. --------------------------------------------------------------------------------
  4901.  
  4902. if exists (select * from sysobjects
  4903.     where type = 'P' and name = 'sp_MSscript_insert_pubwins')
  4904. drop procedure sp_MSscript_insert_pubwins
  4905. go
  4906. raiserror('Creating procedure sp_MSscript_insert_pubwins', 0,1)
  4907. go
  4908. create procedure sp_MSscript_insert_pubwins 
  4909. (
  4910.     @publication sysname        -- publication name
  4911.     ,@article sysname            -- article name
  4912.     ,@objid int                -- object id
  4913.     ,@columns binary(32)        -- columns replicated
  4914. )
  4915. as
  4916. begin
  4917.     declare @cmd nvarchar(4000)
  4918.             ,@artid int
  4919.             ,@pubid int
  4920.             ,@dest_table sysname
  4921.             ,@dest_owner nvarchar(260)
  4922.             ,@rc           int
  4923.             ,@qualname nvarchar(512)
  4924.             ,@fhasnonpkuniquekeys int
  4925.  
  4926.     --
  4927.     -- initialize the vars we will use
  4928.     --
  4929.     select @pubid = pubid from syspublications where name = @publication
  4930.     select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner
  4931.     from sysarticles where name = @article and pubid = @pubid
  4932.     select @dest_owner = case when (@dest_owner IS NULL) then N''
  4933.                 else quotename(@dest_owner) + N'.' end
  4934.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  4935.     --
  4936.     --  check if this article has non PK unique keys
  4937.     --
  4938.     exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
  4939.     --
  4940.     -- start scripting
  4941.     --
  4942.     select @cmd = N'
  4943.     if (@execution_mode = @QPubWins)
  4944.     begin
  4945.         '+N'--
  4946.         '+N'-- Publisher wins resolution
  4947.         '+N'-- '
  4948.     insert into #proctext(procedure_text) values( @cmd )
  4949.     --
  4950.     -- declare fetch variables for cursor
  4951.     --
  4952.     exec @rc = sp_scriptpubwinsrefreshcursorvars @objid
  4953.     --
  4954.     -- continue scripting
  4955.     --
  4956.     select @cmd = N'
  4957.  
  4958.         '+N'--
  4959.         '+N'-- --------------------------------------------------------------------
  4960.         '+N'-- Perform single row delete generations first
  4961.         '+N'-- --------------------------------------------------------------------
  4962.         '+N'--'
  4963.     insert into #proctext(procedure_text) values( @cmd )
  4964.     --
  4965.     -- continue scripting
  4966.     --
  4967.     select @cmd = N'
  4968.  
  4969.         '+N'--
  4970.         '+N'-- Generate DELETE for PK
  4971.         '+N'--
  4972.         if (@cftcase in (21,22,23))
  4973.         begin'
  4974.     insert into #proctext(procedure_text) values( @cmd )
  4975.     --
  4976.     -- Generate the delete compensating code
  4977.     --
  4978.     select @cmd = N'
  4979.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  4980.         + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  4981.     insert into #proctext(procedure_text) values( @cmd )
  4982.     exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'ins'
  4983.     --
  4984.     -- generate the send command
  4985.     --
  4986.     exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  4987.     --
  4988.     -- continue scripting
  4989.     --
  4990.     select @cmd = N'
  4991.         end
  4992.  
  4993.         '+N'--
  4994.         '+N'-- --------------------------------------------------------------------
  4995.         '+N'-- Perform refresh(delete+insert) generations next
  4996.         '+N'-- --------------------------------------------------------------------
  4997.         '+N'--'
  4998.     insert into #proctext(procedure_text) values( @cmd )
  4999.     --
  5000.     -- script this block if the article has non PK unique keys
  5001.     --
  5002.     if (@fhasnonpkuniquekeys = 1)
  5003.     begin
  5004.         select @cmd = N'
  5005.  
  5006.         '+N'--
  5007.         '+N'-- Generate delete+insert for values of non PK keys
  5008.         '+N'--
  5009.         if (@cftcase = 22)
  5010.         begin'
  5011.         insert into #proctext(procedure_text) values( @cmd )
  5012.         --
  5013.         -- generate delete compensating command for values of non PK unique keys
  5014.         --
  5015.         select @cmd = N'
  5016.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5017.                     + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5018.         insert into #proctext(procedure_text) values( @cmd )
  5019.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5020.                     ,@columns = @columns
  5021.                     ,@prefix = N'@c' 
  5022.                     ,@suffix = NULL
  5023.                     ,@mode = 5
  5024.         --
  5025.         -- script the sending command
  5026.         --
  5027.         exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5028.         --
  5029.         -- script the refresh commands for values of non PK unique keys
  5030.         --
  5031.         exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 3, 0
  5032.         if (@rc != 0 or @@error != 0)
  5033.             return 1
  5034.         --
  5035.         -- continue scripting
  5036.         --
  5037.         select @cmd = N'
  5038.         end'
  5039.         insert into #proctext(procedure_text) values( @cmd )
  5040.     end
  5041.     --
  5042.     -- continue scripting
  5043.     --
  5044.     select @cmd = N'
  5045.         '+N'--
  5046.         '+N'-- Generate delete+insert for values of all keys
  5047.         '+N'--
  5048.         if (@cftcase = 21)
  5049.         begin'
  5050.     insert into #proctext(procedure_text) values( @cmd )
  5051.     --
  5052.     -- generate delete compensating command for values of all unique keys
  5053.     --
  5054.     select @cmd = N'
  5055.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5056.         + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5057.     insert into #proctext(procedure_text) values( @cmd )
  5058.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5059.                 ,@columns = @columns
  5060.                 ,@prefix = N'@c' 
  5061.                 ,@suffix = NULL
  5062.                 ,@mode = 4
  5063.     --
  5064.     -- script the sending command
  5065.     --
  5066.     exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5067.     --
  5068.     -- script the refresh commands for values of all unique keys
  5069.     --
  5070.     exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 5, 0
  5071.     if (@rc != 0 or @@error != 0)
  5072.         return 1
  5073.     --
  5074.     -- continue scripting
  5075.     --
  5076.     select @cmd = N'
  5077.         end
  5078.         '+N'--
  5079.         '+N'-- --------------------------------------------------------------------
  5080.         '+N'-- all done for conflict resolution for Publisher Wins policy
  5081.         '+N'-- --------------------------------------------------------------------
  5082.         '+N'--
  5083.     end'
  5084.     insert into #proctext(procedure_text) values( @cmd )
  5085.     --
  5086.     -- all done
  5087.     --
  5088.     return 0
  5089. end
  5090. go
  5091. exec dbo.sp_MS_marksystemobject sp_MSscript_insert_pubwins
  5092. go
  5093.  
  5094. --------------------------------------------------------------------------------
  5095. --. sp_MSscript_update_subwins
  5096. --------------------------------------------------------------------------------
  5097.  
  5098. if exists (select * from sysobjects
  5099.     where type = 'P' and name = 'sp_MSscript_update_subwins')
  5100. drop procedure sp_MSscript_update_subwins
  5101. go
  5102. raiserror('Creating procedure sp_MSscript_update_subwins', 0,1)
  5103. go
  5104. create procedure sp_MSscript_update_subwins 
  5105. (
  5106.     @publication sysname        -- publication name
  5107.     ,@article sysname            -- article name
  5108.     ,@objid int                -- object id
  5109.     ,@columns binary(32)        -- columns replicated
  5110.     ,@identity_insert bit
  5111. )
  5112. AS
  5113. BEGIN
  5114.     declare @cmd nvarchar(4000)
  5115.             ,@artid int
  5116.             ,@pubid int
  5117.             ,@qualname nvarchar(512)
  5118.             ,@rc           int
  5119.             ,@fhasnonpkuniquekeys int
  5120.  
  5121.     --
  5122.     -- initialize the vars we will use
  5123.     --
  5124.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  5125.     --
  5126.     --  check if this article has non PK unique keys
  5127.     --
  5128.     exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
  5129.     --
  5130.     -- start scripting
  5131.     --
  5132.     select @cmd = N'
  5133.     if (@execution_mode = @QSubWins)
  5134.     begin
  5135.         ' + N'--
  5136.         ' + N'-- Subscriber wins resolution
  5137.         ' + N'-- 
  5138.         if (@cftcase in (10,11,14,15,18,20,21,22))
  5139.         begin
  5140.             '+N'--
  5141.             '+N'-- delete the row with OLD_PK
  5142.             '+N'--'
  5143.     insert into #proctext(procedure_text) values( @cmd )
  5144.     --
  5145.     -- script delete with PK=OLD_PK
  5146.     --
  5147.     select @cmd = N'
  5148.             delete ' + @qualname 
  5149.     insert into #proctext(procedure_text) values( @cmd )
  5150.     exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
  5151.     --
  5152.     -- continue scripting
  5153.     --
  5154.     select @cmd = N'
  5155.         end'
  5156.     insert into #proctext(procedure_text) values( @cmd )
  5157.     --
  5158.     -- if the table has non PK unique keys
  5159.     -- generate the commands for non PK keys
  5160.     --
  5161.     if (@fhasnonpkuniquekeys = 1)
  5162.     begin
  5163.         select @cmd = N'
  5164.         if (@cftcase in (17,20,22,23))
  5165.         begin
  5166.             '+N'--
  5167.             '+N'-- delete with NEW values of non PK keys
  5168.             '+N'--'
  5169.         insert into #proctext(procedure_text) values( @cmd )
  5170.         --
  5171.         -- script delete with NEW values of non PK keys
  5172.         --
  5173.         select @cmd = N'
  5174.             delete ' + @qualname 
  5175.         insert into #proctext(procedure_text) values( @cmd )
  5176.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5177.                     ,@columns = @columns
  5178.                     ,@prefix = N'@c' 
  5179.                     ,@suffix = NULL
  5180.                     ,@mode = 7
  5181.         --
  5182.         -- continue scripting
  5183.         --
  5184.         select @cmd = N'
  5185.         end'
  5186.         insert into #proctext(procedure_text) values( @cmd )
  5187.     end
  5188.     --
  5189.     -- continue scripting
  5190.     --
  5191.     select @cmd = N'
  5192.         if (@cftcase in (15,16))
  5193.         begin
  5194.             '+N'--
  5195.             '+N'-- delete with NEW values of all keys
  5196.             '+N'--'
  5197.     insert into #proctext(procedure_text) values( @cmd )
  5198.     --
  5199.     -- script delete with NEW values of all keys
  5200.     --
  5201.     select @cmd = N'
  5202.             delete ' + @qualname 
  5203.     insert into #proctext(procedure_text) values( @cmd )
  5204.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5205.                 ,@columns = @columns
  5206.                 ,@prefix = N'@c' 
  5207.                 ,@suffix = NULL
  5208.                 ,@mode = 6
  5209.     --
  5210.     -- continue scripting
  5211.     --
  5212.     select @cmd = N'
  5213.         end
  5214.         if (@cftcase in (10,11,12,13,14,15,16,17,18,20,21,22,23,24))
  5215.         begin
  5216.             '+N'--
  5217.             '+N'-- insert with NEW values of all keys
  5218.             '+N'--'
  5219.     insert into #proctext(procedure_text) values( @cmd )
  5220.     --
  5221.     --  
  5222.     -- generate insert statement with NEW values 
  5223.     --
  5224.     exec @rc = sp_script_insertforcftresolution 
  5225.             @objid = @objid
  5226.             ,@columns = @columns
  5227.             ,@identity_insert = @identity_insert
  5228.             ,@prefix = N'@c'
  5229.             ,@suffix = NULL
  5230.     --
  5231.     -- continue scripting
  5232.     --
  5233.     select @cmd = N'
  5234.         end
  5235.  
  5236.         ' + N'--
  5237.         ' + N'-- --------------------------------------------------------------------
  5238.         ' + N'-- all done for conflict resolution for Subscriber Wins policy
  5239.         ' + N'-- --------------------------------------------------------------------
  5240.         ' + N'--
  5241.     end'
  5242.     insert into #proctext(procedure_text) values( @cmd )
  5243.     --
  5244.     -- all done
  5245.     --
  5246.     return 0
  5247. END
  5248. go
  5249. exec dbo.sp_MS_marksystemobject sp_MSscript_update_subwins
  5250. go
  5251.  
  5252. --------------------------------------------------------------------------------
  5253. --. sp_MSscript_update_pubwins
  5254. --------------------------------------------------------------------------------
  5255.  
  5256. if exists (select * from sysobjects
  5257.     where type = 'P' and name = 'sp_MSscript_update_pubwins')
  5258. drop procedure sp_MSscript_update_pubwins
  5259. go
  5260. raiserror('Creating procedure sp_MSscript_update_pubwins', 0,1)
  5261. go
  5262. create procedure sp_MSscript_update_pubwins 
  5263. (
  5264.     @publication sysname        -- publication name
  5265.     ,@article sysname            -- article name
  5266.     ,@objid int                -- object id
  5267.     ,@columns binary(32)        -- columns replicated
  5268. )
  5269. as
  5270. begin
  5271.     declare @cmd nvarchar(4000)
  5272.             ,@artid int
  5273.             ,@pubid int
  5274.             ,@qualname nvarchar(512)
  5275.             ,@dest_table sysname
  5276.             ,@dest_owner nvarchar(260)
  5277.             ,@rc           int
  5278.             ,@fhasnonpkuniquekeys int
  5279.  
  5280.     --
  5281.     -- initialize the vars we will use
  5282.     --
  5283.     select @pubid = pubid from syspublications where name = @publication
  5284.     select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner
  5285.     from sysarticles where name = @article and pubid = @pubid
  5286.     select @dest_owner = case when (@dest_owner IS NULL) then N''
  5287.                 else quotename(@dest_owner) + N'.' end
  5288.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  5289.     --
  5290.     --  check if this article has non PK unique keys
  5291.     --
  5292.     exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
  5293.     --
  5294.     -- start scripting
  5295.     --
  5296.     select @cmd = N'
  5297.     
  5298.     ' + N'-- 
  5299.     ' + N'--  --------------------------------------------------------------------
  5300.     ' + N'--  Now the generation phase
  5301.     ' + N'--  Use the conflict case value to decide what to do
  5302.     ' + N'--  --------------------------------------------------------------------
  5303.     ' + N'--
  5304.     '
  5305.     insert into #proctext(procedure_text) values( @cmd )
  5306.     select @cmd = N'
  5307.     
  5308.     if (@execution_mode = @QPubWins)
  5309.     begin
  5310.         ' + N'-- 
  5311.         ' + N'--  Publisher wins resolution
  5312.         ' + N'--  
  5313.         '
  5314.     insert into #proctext(procedure_text) values( @cmd )
  5315.     --
  5316.     -- declare fetch variables for cursor
  5317.     --
  5318.     exec @rc = sp_scriptpubwinsrefreshcursorvars @objid
  5319.     --
  5320.     -- continue scripting
  5321.     --
  5322.     select @cmd = N'
  5323.         ' + N'-- 
  5324.         ' + N'--  --------------------------------------------------------------------
  5325.         ' + N'--  Perform single row delete generations first
  5326.         ' + N'--  --------------------------------------------------------------------
  5327.         ' + N'-- 
  5328.         '
  5329.     insert into #proctext(procedure_text) values( @cmd )
  5330.     select @cmd = N'
  5331.         ' + N'-- 
  5332.         ' + N'--  Generate DELETE for PK = OLD_PK
  5333.         ' + N'-- 
  5334.         if (@cftcase in (11,12,13,16,18,21,22,23,24))
  5335.         begin'
  5336.     insert into #proctext(procedure_text) values( @cmd )
  5337.     --
  5338.     -- generate delete compensating cmd with OLD_PK
  5339.     --
  5340.     select @cmd = N'
  5341.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5342.         + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5343.     insert into #proctext(procedure_text) values( @cmd )
  5344.     exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'del'
  5345.     --
  5346.     -- script the sending command
  5347.     --
  5348.     exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5349.     --
  5350.     -- continue scripting
  5351.     --
  5352.     select @cmd = N'
  5353.         end
  5354.         ' + N'-- 
  5355.         ' + N'--  Generate DELETE for PK = NEW_PK 
  5356.         ' + N'-- 
  5357.         if (@cftcase in (1,12,14))
  5358.         begin'
  5359.     insert into #proctext(procedure_text) values( @cmd )        
  5360.     --
  5361.     -- generate delete compensating cmd with NEW_PK
  5362.     --
  5363.     select @cmd = N'
  5364.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5365.         + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5366.     insert into #proctext(procedure_text) values( @cmd )
  5367.     exec dbo.sp_MSscript_where_clause @objid, @columns, 'qcft_comp', NULL, 0, 'ins'
  5368.     --
  5369.     -- script the sending command
  5370.     --
  5371.     exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5372.     --
  5373.     -- continue scripting
  5374.     --
  5375.     select @cmd = N'
  5376.         end'
  5377.     insert into #proctext(procedure_text) values( @cmd )
  5378.     --
  5379.     -- this scripting is specific to non PK unique keys
  5380.     --
  5381.     if (@fhasnonpkuniquekeys = 1)
  5382.     begin
  5383.         --
  5384.         -- continue scripting
  5385.         --
  5386.         select @cmd = N'
  5387.  
  5388.         '+N'--
  5389.         '+N'-- Generate delete for OLD values of non PK keys
  5390.         '+N'--
  5391.         if (@cftcase in (17,18,23,24))
  5392.         begin'
  5393.         insert into #proctext(procedure_text) values( @cmd )
  5394.         --
  5395.         -- generate delete compensating command for OLD values of non PK unique keys
  5396.         --
  5397.         select @cmd = N'
  5398.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5399.                     + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5400.         insert into #proctext(procedure_text) values( @cmd )
  5401.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5402.                 ,@columns = @columns
  5403.                 ,@prefix = N'@c' 
  5404.                 ,@suffix = N'_old'
  5405.                 ,@mode = 5
  5406.         --
  5407.         -- script the sending command
  5408.         --
  5409.         exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5410.         --
  5411.         -- continue scripting
  5412.         --
  5413.         select @cmd = N'
  5414.         end
  5415.  
  5416.         '+N'--
  5417.         '+N'-- Generate delete for NEW values of non PK keys
  5418.         '+N'--
  5419.         if (@cftcase in (10,18,21,24))
  5420.         begin'
  5421.         insert into #proctext(procedure_text) values( @cmd )
  5422.         --
  5423.         -- generate delete compensating command for NEW values of non PK unique keys
  5424.         --
  5425.         select @cmd = N'
  5426.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5427.                     + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5428.         insert into #proctext(procedure_text) values( @cmd )
  5429.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5430.                     ,@columns = @columns
  5431.                     ,@prefix = N'@c' 
  5432.                     ,@suffix = NULL
  5433.                     ,@mode = 5
  5434.         --
  5435.         -- script the sending command
  5436.         --
  5437.         exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5438.         --
  5439.         -- continue scripting
  5440.         --
  5441.         select @cmd = N'
  5442.         end
  5443.  
  5444.         ' + N'-- 
  5445.         ' + N'--  --------------------------------------------------------------------
  5446.         ' + N'--  Perform refresh(delete+insert) generations next
  5447.         ' + N'--  --------------------------------------------------------------------
  5448.         ' + N'-- 
  5449.         
  5450.         ' + N'-- 
  5451.         ' + N'--  Generate delete+insert for OLD values of non PK keys
  5452.         ' + N'-- 
  5453.         if (@cftcase in (21,22))
  5454.         begin'
  5455.         insert into #proctext(procedure_text) values( @cmd )
  5456.         --
  5457.         -- generate delete compensating command for OLD values of non PK unique keys
  5458.         --
  5459.         select @cmd = N'
  5460.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5461.                     + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5462.         insert into #proctext(procedure_text) values( @cmd )
  5463.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5464.                 ,@columns = @columns
  5465.                 ,@prefix = N'@c' 
  5466.                 ,@suffix = N'_old'
  5467.                 ,@mode = 5
  5468.         --
  5469.         -- script the sending command
  5470.         --
  5471.         exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5472.         --
  5473.         -- script the refresh commands for OLD values of non PK unique keys
  5474.         --
  5475.         exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 2, 0
  5476.         if (@rc != 0 or @@error != 0)
  5477.             return 1
  5478.         --
  5479.         -- continue scripting
  5480.         --
  5481.         select @cmd = N'
  5482.         end
  5483.         ' + N'-- 
  5484.         ' + N'--  Generate delete+insert for NEW values of non PK keys
  5485.         ' + N'-- 
  5486.         if (@cftcase in (20,22,23))
  5487.         begin'
  5488.         insert into #proctext(procedure_text) values( @cmd )
  5489.         --
  5490.         -- generate delete compensating command for NEW values of non PK unique keys
  5491.         --
  5492.         select @cmd = N'
  5493.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5494.                     + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5495.         insert into #proctext(procedure_text) values( @cmd )
  5496.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5497.                     ,@columns = @columns
  5498.                     ,@prefix = N'@c' 
  5499.                     ,@suffix = NULL
  5500.                     ,@mode = 5
  5501.         --
  5502.         -- script the sending command
  5503.         --
  5504.         exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5505.         --
  5506.         -- script the refresh commands for NEW values of non PK unique keys
  5507.         --
  5508.         exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 3, 0
  5509.         if (@rc != 0 or @@error != 0)
  5510.             return 1
  5511.         --
  5512.         -- continue scripting
  5513.         --
  5514.         select @cmd = N'
  5515.         end'
  5516.         insert into #proctext(procedure_text) values( @cmd )
  5517.     end
  5518.     --
  5519.     -- continue scripting
  5520.     --
  5521.     select @cmd = N'
  5522.  
  5523.         ' + N'-- 
  5524.         ' + N'--  Generate delete+insert for OLD values of all keys
  5525.         ' + N'-- 
  5526.         if (@cftcase in (1,3,10,14,15,20))
  5527.         begin'
  5528.     insert into #proctext(procedure_text) values( @cmd )
  5529.     --
  5530.     -- generate delete compensating command for OLD values of all unique keys
  5531.     --
  5532.     select @cmd = N'
  5533.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5534.         + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5535.     insert into #proctext(procedure_text) values( @cmd )
  5536.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5537.                 ,@columns = @columns
  5538.                 ,@prefix = N'@c' 
  5539.                 ,@suffix = N'_old'
  5540.                 ,@mode = 4
  5541.     --
  5542.     -- script the sending command
  5543.     --
  5544.     exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5545.     --
  5546.     -- script the refresh commands for OLD values of all unique keys
  5547.     --
  5548.     exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 4, 0
  5549.     if (@rc != 0 or @@error != 0)
  5550.         return 1
  5551.     --
  5552.     -- continue scripting
  5553.     --
  5554.     select @cmd = N'
  5555.         end
  5556.         ' + N'-- 
  5557.         ' + N'--  Generate delete+insert for NEW values of all keys
  5558.         ' + N'-- 
  5559.         if (@cftcase in (15,16,17))
  5560.         begin'
  5561.     insert into #proctext(procedure_text) values( @cmd )
  5562.     --
  5563.     -- generate delete compensating command for NEW values of all unique keys
  5564.     --
  5565.     select @cmd = N'
  5566.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5567.         + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5568.     insert into #proctext(procedure_text) values( @cmd )
  5569.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5570.                 ,@columns = @columns
  5571.                 ,@prefix = N'@c' 
  5572.                 ,@suffix = NULL
  5573.                 ,@mode = 4
  5574.     --
  5575.     -- script the sending command
  5576.     --
  5577.     exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5578.     --
  5579.     -- script the refresh commands for NEW values of all unique keys
  5580.     --
  5581.     exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 5, 0
  5582.     if (@rc != 0 or @@error != 0)
  5583.         return 1
  5584.     --
  5585.     -- continue scripting
  5586.     --
  5587.     select @cmd = N'
  5588.         end
  5589.  
  5590.         ' + N'-- 
  5591.         ' + N'--  --------------------------------------------------------------------
  5592.         ' + N'--  Perform single row insert generations next
  5593.         ' + N'--  --------------------------------------------------------------------
  5594.         ' + N'-- 
  5595.  
  5596.         ' + N'-- 
  5597.         ' + N'--  Generate INSERT for PK = OLD_PK
  5598.         ' + N'-- 
  5599.         if (@cftcase in (11,18))
  5600.         begin'
  5601.     insert into #proctext(procedure_text) values( @cmd )
  5602.     --
  5603.     -- script compensating insert with OLD_PK
  5604.     --
  5605.     exec dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 1, 0
  5606.     --
  5607.     -- continue scripting
  5608.     --
  5609.     select @cmd = N'
  5610.         end
  5611.  
  5612.         ' + N'-- 
  5613.         ' + N'--  --------------------------------------------------------------------
  5614.         ' + N'--  all done for conflict resolution for Publisher Wins policy
  5615.         ' + N'--  --------------------------------------------------------------------
  5616.         ' + N'-- 
  5617.     end'
  5618.     insert into #proctext(procedure_text) values( @cmd )
  5619.     --
  5620.     -- all done
  5621.     --
  5622.     return 0    
  5623. end
  5624. go
  5625. exec dbo.sp_MS_marksystemobject sp_MSscript_update_pubwins
  5626. go
  5627.  
  5628. --------------------------------------------------------------------------------
  5629. --. sp_MSscript_compensating_insert
  5630. --------------------------------------------------------------------------------
  5631.  
  5632. if exists (select * from sysobjects
  5633.     where type = 'P' and name = 'sp_MSscript_compensating_insert')
  5634. drop procedure sp_MSscript_compensating_insert
  5635. go
  5636. raiserror('Creating procedure sp_MSscript_compensating_insert', 0,1)
  5637. go
  5638. create procedure sp_MSscript_compensating_insert 
  5639. (
  5640.     @publication sysname     -- publication name
  5641.     ,@article sysname         -- article name
  5642.     ,@objid int            -- table object id
  5643.     ,@columns binary(32)    -- columns replicated
  5644.     ,@proctype tinyint        -- what are we scripting         
  5645.     -- 0 = use new_pk
  5646.     -- 1 = use old_pk
  5647.     -- 2 = use old nonpkkeys
  5648.     -- 3 = use new nonpkkeys
  5649.     -- 4 = use oldallkeys
  5650.     -- 5 = use newallkeys
  5651.     ,@fdodeclare bit = 1    -- 0 = do not script declares for non PK unique key processing
  5652. )
  5653. as
  5654. begin
  5655.     declare @cmd nvarchar(4000)
  5656.             ,@artid int
  5657.             ,@pubid int
  5658.             ,@dest_table sysname
  5659.             ,@dest_owner nvarchar(260)
  5660.             ,@colname      sysname
  5661.             ,@ccoltype     sysname
  5662.             ,@this_col     int
  5663.             ,@rc           int
  5664.             ,@num_col      int
  5665.             ,@qualname nvarchar(540)
  5666.             ,@cast_str nvarchar(4000)
  5667.             ,@column_string nvarchar(4000)
  5668.             ,@ins_cmd nvarchar(255)
  5669.             ,@startoffset int
  5670.             ,@setprefix bit
  5671.             ,@commandlen int
  5672.             ,@fragmentlen int
  5673.             ,@collen int
  5674.             ,@first_time bit
  5675.             ,@fullcastlen int
  5676.             ,@splitlen int
  5677.             ,@pkcolumns varbinary(32)
  5678.             ,@fhasnonpkuniquekeys int
  5679.     declare @pkfetch table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  5680.     --
  5681.     -- constants
  5682.     --
  5683.     declare @typeusenew_pk tinyint
  5684.             ,@typeuseold_pk tinyint
  5685.             ,@typeuseoldnonpkkeys tinyint
  5686.             ,@typeusenewnonpkkeys tinyint
  5687.             ,@typeuseoldallkeys tinyint
  5688.             ,@typeusenewallkeys tinyint
  5689.     --
  5690.     -- initialize constants
  5691.     --
  5692.     select @typeusenew_pk = 0
  5693.             ,@typeuseold_pk = 1
  5694.             ,@typeuseoldnonpkkeys = 2
  5695.             ,@typeusenewnonpkkeys = 3
  5696.             ,@typeuseoldallkeys = 4
  5697.             ,@typeusenewallkeys = 5
  5698.  
  5699.     --
  5700.     -- validate @proctype
  5701.     --
  5702.     if (@proctype not in (@typeusenew_pk,@typeuseold_pk,@typeuseoldnonpkkeys,
  5703.         @typeusenewnonpkkeys,@typeuseoldallkeys,@typeusenewallkeys))
  5704.     begin
  5705.         -- raiserror invalid proctype
  5706.         return 1
  5707.     end
  5708.     --
  5709.     -- initialize the vars we will use
  5710.     --
  5711.     select @pubid = pubid from syspublications where name = @publication
  5712.     select @artid = artid, @dest_table = dest_table, 
  5713.         @dest_owner = dest_owner, @ins_cmd = ins_cmd from sysarticles 
  5714.     where name = @article and pubid = @pubid
  5715.     select @dest_owner = case when (@dest_owner IS NULL) then N''
  5716.                 else quotename(@dest_owner) + N'.' end
  5717.             ,@fhasnonpkuniquekeys = 0
  5718.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  5719.     --
  5720.     -- Do we have non PK unique keys
  5721.     --
  5722.     exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @objid
  5723.     --
  5724.     -- If we are generating refreshing commands
  5725.     -- we will be using cursors
  5726.     --
  5727.     if (@proctype in (@typeuseoldnonpkkeys,@typeusenewnonpkkeys
  5728.                         ,@typeuseoldallkeys,@typeusenewallkeys))
  5729.     begin
  5730.         --
  5731.         -- generate cursor to collect PK for selected rowset
  5732.         -- and then perform delete compensation followed by
  5733.         -- insert compensation
  5734.         --
  5735.          declare @cmd2 nvarchar(4000)
  5736.             ,@cmd3 nvarchar(4000)
  5737.             ,@spacer nvarchar(5)
  5738.             ,@typestring sysname
  5739.             ,@isset int
  5740.             ,@wheremode tinyint
  5741.             ,@suffix nvarchar(10)
  5742.         declare @pkvars table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  5743.         declare @pkcols table ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  5744.  
  5745.         --
  5746.         -- if the article has no non PK unique keys
  5747.         -- we should not be processing for @typeuseoldnonpkkeys,@typeusenewnonpkkeys
  5748.         --
  5749.         if (@fhasnonpkuniquekeys = 0 and 
  5750.             @proctype in (@typeuseoldnonpkkeys,@typeusenewnonpkkeys))
  5751.         begin
  5752.             -- error we should not generate these cases if there are no non PK unique keys
  5753.             return 1
  5754.         end
  5755.         --
  5756.         -- build some strings for PK columns and PK variables (@pkc1..)
  5757.         --
  5758.         exec dbo.sp_getarticlepkcolbitmap @objid, @pkcolumns output
  5759.         select @cmd = N''
  5760.             ,@cmd2 = N''
  5761.             ,@cmd3 = N''
  5762.             ,@spacer = N''
  5763.         declare #hccolid cursor local fast_forward for 
  5764.             select colid, name from syscolumns where id = @objid order by colid asc
  5765.         open #hccolid
  5766.         fetch #hccolid into @this_col, @colname
  5767.         while (@@fetch_status != -1)
  5768.         begin
  5769.             exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
  5770.             if @isset != 0 and (@colname is not null)
  5771.             begin
  5772.                 exec dbo.sp_gettypestring @objid, @this_col, @typestring output
  5773.                 select @cmd = @cmd + @spacer + N'@pkc' + convert( nvarchar, @this_col ) + N' ' + @typestring 
  5774.                         ,@cmd2 = @cmd2 + @spacer + quotename(@colname)
  5775.                         ,@cmd3 = @cmd3 + @spacer + N'@pkc' + convert( nvarchar, @this_col )
  5776.                 select @spacer = N','
  5777.  
  5778.                 if len( @cmd ) > 3000
  5779.                 begin
  5780.                     insert into @pkvars(procedure_text) values( @cmd )
  5781.                     select @cmd = N''
  5782.                 end
  5783.                 if len( @cmd2 ) > 3000
  5784.                 begin
  5785.                     insert into @pkcols(procedure_text) values( @cmd2 )
  5786.                     select @cmd2 = N''
  5787.                 end
  5788.                 if len( @cmd3 ) > 3000
  5789.                 begin
  5790.                     insert into @pkfetch(procedure_text) values( @cmd3 )
  5791.                     select @cmd3 = N''
  5792.                 end
  5793.             end
  5794.             fetch #hccolid into @this_col, @colname
  5795.         end
  5796.         close #hccolid
  5797.         deallocate #hccolid
  5798.         if len(@cmd) > 0
  5799.             insert into @pkvars(procedure_text) values( @cmd )
  5800.         if len(@cmd2) > 0
  5801.             insert into @pkcols(procedure_text) values( @cmd2 )
  5802.         if len(@cmd3) > 0
  5803.             insert into @pkfetch(procedure_text) values( @cmd3 )
  5804.         --
  5805.         -- script the PK variable declare now
  5806.         --
  5807.         if (@fdodeclare = 1)
  5808.         begin
  5809.             select @cmd = N'
  5810.             declare '
  5811.             insert into #proctext(procedure_text) values( @cmd )
  5812.             insert into #proctext(procedure_text) 
  5813.                 select procedure_text from @pkvars order by c1 asc
  5814.         end
  5815.         --
  5816.         -- script the cursor declare now
  5817.         --
  5818.         select @cmd = N'
  5819.             declare #hccompins cursor local fast_forward for 
  5820.                 select distinct '
  5821.         insert into #proctext(procedure_text) values( @cmd )
  5822.         insert into #proctext(procedure_text) 
  5823.             select procedure_text from @pkcols order by c1 asc
  5824.         select @cmd = N'
  5825.             from ' + @qualname 
  5826.         insert into #proctext(procedure_text) values( @cmd )
  5827.         --
  5828.         -- script the where clause for the cursor
  5829.         -- based on @proctype
  5830.         --
  5831.         if (@proctype = @typeuseoldnonpkkeys) 
  5832.         begin
  5833.             select @wheremode = 7
  5834.                 ,@suffix = N'_old'
  5835.         end
  5836.           else if (@proctype = @typeusenewnonpkkeys) 
  5837.           begin
  5838.             select @wheremode = 7
  5839.                 ,@suffix = NULL
  5840.           end
  5841.           else if (@proctype = @typeuseoldallkeys) 
  5842.           begin
  5843.             select @wheremode = 6
  5844.                 ,@suffix = N'_old'
  5845.           end
  5846.           else if (@proctype = @typeusenewallkeys) 
  5847.           begin
  5848.             select @wheremode = 6
  5849.                 ,@suffix = NULL
  5850.         end
  5851.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5852.                     ,@columns = @columns
  5853.                     ,@prefix = N'@c' 
  5854.                     ,@suffix = @suffix
  5855.                     ,@mode = @wheremode
  5856.         --
  5857.         -- script the cursor open and fetch
  5858.         --
  5859.         select @cmd = N'
  5860.             open #hccompins
  5861.             fetch #hccompins into '
  5862.         insert into #proctext(procedure_text) values( @cmd )
  5863.         insert into #proctext(procedure_text) 
  5864.             select procedure_text from @pkfetch order by c1 asc
  5865.         select @cmd = N'
  5866.             while (@@fetch_status != -1)
  5867.             begin '
  5868.         insert into #proctext(procedure_text) values( @cmd )
  5869.         --
  5870.         -- we are processing a refresh process
  5871.         -- issue a compensating delete for the row
  5872.         -- select in the cursor
  5873.         --
  5874.         select @cmd = N'
  5875.             ' + '--
  5876.             ' + '-- Issue a delete command for row selected in cursor
  5877.             ' + '-- '
  5878.         insert into #proctext(procedure_text) values( @cmd )
  5879.         select @cmd = N'
  5880.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5881.             + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  5882.         insert into #proctext(procedure_text) values( @cmd )
  5883.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  5884.                     ,@columns = @columns
  5885.                     ,@prefix = N'@pkc' 
  5886.                     ,@suffix = NULL
  5887.                     ,@mode = 8
  5888.         --
  5889.         -- script the send for this command
  5890.         --
  5891.         exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  5892.         --
  5893.         -- continue scripting
  5894.         --
  5895.         select @cmd = N'
  5896.             ' + '--
  5897.             ' + '-- Issue a compensating insert for row selected in cursor
  5898.             ' + '-- '
  5899.         insert into #proctext(procedure_text) values( @cmd )
  5900.     end
  5901.     --
  5902.     -- The compensating command will be split into one or more
  5903.     -- fragment commands if the length exceeds 3450 characters in length 
  5904.     -- (to accomodate compensating server/db names)
  5905.     -- For correctly estimating the length of the compensating command
  5906.     -- we have to take the max column length of the data into consideration along
  5907.     -- with the scripting command length
  5908.     --
  5909.  
  5910.     --
  5911.     -- use the insert command if available
  5912.     --
  5913.     select @commandlen = 0
  5914.             ,@setprefix = 1
  5915.  
  5916.     if (@ins_cmd = N'SQL')
  5917.     begin
  5918.         select @cmd = N'
  5919.             select @cmd = ''INSERT INTO ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  5920.                         + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N''' + 
  5921.                         '' SELECT '' + '
  5922.     end
  5923.     else
  5924.     begin
  5925.         select @cmd = N'
  5926.             select @cmd = ''EXEC ' + substring(@ins_cmd, 5, len(@ins_cmd) - 4) + N' '' + '
  5927.     end
  5928.     insert into #proctext(procedure_text) values( @cmd )
  5929.      select @commandlen = @commandlen + len(@cmd)
  5930.     
  5931.     select @num_col = 0
  5932.     DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  5933.     select colid, length from syscolumns where id = @objid order by colid asc
  5934.  
  5935.     OPEN hCColid
  5936.     FETCH hCColid INTO @this_col, @collen
  5937.     WHILE (@@fetch_status != -1)
  5938.     begin
  5939.         exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 1, @colname output, @ccoltype output
  5940.         if @rc = 0  and EXISTS (select name from syscolumns where id=@objid and colid=@this_col and iscomputed<>1)
  5941.         begin
  5942.             if rtrim(@ccoltype) not like N'timestamp' 
  5943.             begin
  5944.                 select @num_col = @num_col + 1
  5945.                 --
  5946.                 -- Compute the command fragment length needed for this column
  5947.                 -- based on the coltype
  5948.                 --                
  5949.                 if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('ntext','text','image'))
  5950.                 begin
  5951.                     --
  5952.                     -- For compensating commands we have to include the text and image data
  5953.                     -- as the custom procs used by Distribution process expects them - as it
  5954.                     -- done for regular transactional replication - but we will only send NULLs
  5955.                     -- as it is not possible to ascertain the size of the data during the generation
  5956.                     --        
  5957.                     select @cast_str = N' ''null'' '
  5958.                     select @fullcastlen = len(@cast_str)
  5959.                     select @fragmentlen = @fullcastlen + 4 + @collen
  5960.                 end
  5961.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
  5962.                 begin
  5963.                     if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
  5964.                         select @collen = (@collen / 2)
  5965.     
  5966.                     select @cast_str = case 
  5967.                             when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
  5968.                                 then N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') '
  5969.                                 else N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr(' + quotename(@colname) + N') collate database_default + '''''''', ''null'') '
  5970.                             end
  5971.        
  5972.                     select @fullcastlen = len(@cast_str)
  5973.                     select @fragmentlen = @fullcastlen + 4 + @collen
  5974.                 end
  5975.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
  5976.                 begin
  5977.                     --
  5978.                     -- each byte has 2 nibbles - we need a char to represent each nibble
  5979.                     --
  5980.                     select @collen = @collen * 2
  5981.                     select @cast_str = N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' + quotename(@colname) + N',1,0) collate database_default, ''null'') '
  5982.                     select @fullcastlen = len(@cast_str)
  5983.                     select @fragmentlen = @fullcastlen + 4 + @collen + 2
  5984.                 end
  5985.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','decimal','numeric'))
  5986.                 begin
  5987.                     select @collen = 40
  5988.                     select @cast_str = N' ISNULL(CAST(' + quotename(@colname) + N' as nvarchar), ''null'') '
  5989.                     select @fragmentlen = len(@cast_str) + @collen
  5990.                 end
  5991.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('float','real'))
  5992.                 begin
  5993.                     select @collen = 60
  5994.                     select @cast_str = N' ISNULL(CONVERT(nvarchar(60),' + quotename(@colname) + N',2), ''null'') '
  5995.                     select @fragmentlen = len(@cast_str) + @collen
  5996.                 end
  5997.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
  5998.                 begin
  5999.                     select @collen = 40
  6000.                     select @cast_str = N' ISNULL(CONVERT(nvarchar(40),' + quotename(@colname) + N',2), ''null'') '
  6001.                     select @fragmentlen = len(@cast_str) + @collen
  6002.                 end
  6003.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
  6004.                 begin
  6005.                     select @collen = 40
  6006.                     select @cast_str = N' ISNULL('''''''' + CAST(' + quotename(@colname) + N' as nvarchar(40)) + '''''''', ''null'') '
  6007.                     select @fragmentlen = len(@cast_str) + @collen
  6008.                 end
  6009.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
  6010.                 begin
  6011.                     select @collen = 40
  6012.                     select @cast_str = N' ISNULL('''''''' + CONVERT(nvarchar(40), ' + quotename(@colname) + N', 112) + N'' '' +  CONVERT(nvarchar(40), ' + quotename(@colname) + N', 114) + '''''''', ''null'') '
  6013.                     select @fragmentlen = len(@cast_str) + @collen
  6014.                 end
  6015.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
  6016.                 begin
  6017.                     --
  6018.                     -- need to revisit this later
  6019.                     --
  6020.                     select @cast_str = N' ISNULL(master.dbo.fn_sqlvarbasetostr(' + quotename(@colname) + N' ) collate database_default, ''null'') '
  6021.                     select @fragmentlen = len(@cast_str) + @collen
  6022.                 end                    
  6023.                 else
  6024.                 begin
  6025.                     select @collen = 40
  6026.                     select @cast_str = N' ISNULL(CAST(' + quotename(@colname) + N' as nvarchar), ''null'') '
  6027.                     select @fragmentlen = len(@cast_str) + @collen
  6028.                 end
  6029.                 --
  6030.                 -- for fixed datatypes - we will not split the data at all we will
  6031.                 -- flush the command script and continue
  6032.                 -- for varying/large datatypes, we will have to split data if necessary
  6033.                 --
  6034.                 if ((lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar','binary','varbinary')) 
  6035.                         and (@fragmentlen + @commandlen > 3450))
  6036.                 begin
  6037.                      --
  6038.                      -- the column length is too big, we have to break the data string
  6039.                      -- initialize
  6040.                      --
  6041.                     if (@num_col = 1)
  6042.                     begin
  6043.                         select @column_string = N'
  6044.                 ' 
  6045.                     end
  6046.                     else
  6047.                     begin
  6048.                         select @column_string = N'
  6049.                 + '','' + ' 
  6050.                     end
  6051.                     --
  6052.                     -- use substring to break the string value in the
  6053.                     -- compensating command
  6054.                     --
  6055.                     select @first_time = 1
  6056.                             ,@startoffset = 1
  6057.                     while (@collen > 0)
  6058.                     begin
  6059.                          select @splitlen = case when ((@first_time = 1) or (@collen > 3450))
  6060.                                                  then (3450 - @commandlen - 30 - @fullcastlen)
  6061.                                                  else @collen end
  6062.                          if (@splitlen < 1)
  6063.                          begin
  6064.                              --
  6065.                              -- we have overcompensated the splitlen
  6066.                              -- set to half of the column length
  6067.                              --
  6068.                              select @splitlen = @collen / 2
  6069.                          end
  6070.                         --
  6071.                         -- Do we need to put quotes (many datatypes need it)
  6072.                         --
  6073.                          if (@first_time = 1)
  6074.                          begin
  6075.                             if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
  6076.                                 select @column_string = case 
  6077.                                     when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('nvarchar', 'nchar'))
  6078.                                         then @column_string + N' ISNULL(''N'''''' + master.dbo.fn_MSgensqescstr( '
  6079.                                         else @column_string + N' ISNULL('''''''' + master.dbo.fn_MSgensqescstr( '
  6080.                                     end
  6081.                             else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
  6082.                                 select @column_string = @column_string + N' ISNULL(master.dbo.fn_varbintohexsubstring(1,' 
  6083.                         end
  6084.                          else
  6085.                          begin
  6086.                             if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
  6087.                                  select @column_string = N' + ISNULL(master.dbo.fn_MSgensqescstr( '
  6088.                             else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
  6089.                                 select @column_string = @column_string + N' + ISNULL(master.dbo.fn_varbintohexsubstring(0,' 
  6090.                          end
  6091.                         --
  6092.                         -- prepare the substring script
  6093.                         --
  6094.                         if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
  6095.                             select @cast_str = N'SUBSTRING(' + quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' +  cast(@splitlen as nvarchar) + N')'
  6096.                         else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
  6097.                             select @cast_str = quotename(@colname) + N', ' + cast(@startoffset as nvarchar) + N', ' +  cast((@splitlen/2) as nvarchar)
  6098.  
  6099.                         if (@first_time = 1)
  6100.                          begin
  6101.                             select @cast_str = @cast_str + N') collate database_default, ''null'') '
  6102.                                     ,@first_time = 0
  6103.                          end
  6104.                          else
  6105.                          begin
  6106.                             if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('varchar','nvarchar','char','nchar'))
  6107.                             begin
  6108.                                 --
  6109.                                 -- for strings the last fragment needs the single
  6110.                                 -- quote to be added for the string
  6111.                                 --
  6112.                                 select @cast_str = @cast_str + N') collate database_default '
  6113.                                 select @cast_str = case 
  6114.                                     when (@collen - @splitlen < 1)
  6115.                                         then @cast_str + N'+ '''''''', '''') '                                            
  6116.                                         else @cast_str + N', '''') ' 
  6117.                                     end
  6118.                             end
  6119.                             else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
  6120.                                 select @cast_str = @cast_str + N') collate database_default, '''') '
  6121.                         end
  6122.                                  
  6123.                         select @column_string = @column_string + @cast_str
  6124.                         insert into #proctext(procedure_text) values( @column_string )
  6125.  
  6126.                         if (@fragmentlen + @commandlen > 3450)
  6127.                         begin
  6128.                             select @cmd = N'
  6129.             from ' + @qualname 
  6130.                             insert into #proctext(procedure_text) values( @cmd )
  6131.                             --
  6132.                             -- script the where clause
  6133.                             --
  6134.                             if (@proctype in (@typeusenew_pk,@typeuseold_pk))
  6135.                             begin
  6136.                                 --
  6137.                                 -- only PK unique key
  6138.                                 --
  6139.                                 if (@proctype = @typeuseold_pk)
  6140.                                     exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
  6141.                                 else
  6142.                                     exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
  6143.                             end
  6144.                             else
  6145.                             begin
  6146.                                 --
  6147.                                 -- we are in the cursor for qualifying row
  6148.                                 -- 
  6149.                                 exec dbo.sp_scriptpkwhereclause @src_objid = @objid
  6150.                                             ,@pkcolumns = @pkcolumns
  6151.                                             ,@prefix = N'@pkc'
  6152.                                             ,@artcolumns = @columns
  6153.                                             ,@mode = 2
  6154.                             end
  6155.                             --
  6156.                             -- Script the compensating send
  6157.                             --
  6158.                             exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
  6159.                             if (@setprefix = 1)
  6160.                                 select @setprefix = 0
  6161.  
  6162.                             select @cmd = N'
  6163.             select @cmd = N''''' 
  6164.                             insert into #proctext(procedure_text) values( @cmd )
  6165.                             select @commandlen = 0
  6166.                         end
  6167.                         else
  6168.                             select @commandlen = @commandlen + len(@column_string)
  6169.                         --
  6170.                         -- update vars for next round
  6171.                         --
  6172.                         select @collen = @collen - @splitlen
  6173.                                 ,@column_string = N''
  6174.                                 ,@startoffset = case 
  6175.                                     when (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary')) 
  6176.                                         then (@splitlen/2) + @startoffset 
  6177.                                         else @splitlen + @startoffset 
  6178.                                     end
  6179.                         select @fragmentlen = @fullcastlen + 4 + @collen
  6180.                     end                            
  6181.                     --
  6182.                     -- we done with this column now
  6183.                     -- skip processing further and continue
  6184.                     --                        
  6185.                     select @commandlen = @commandlen + len(@column_string)
  6186.                  end
  6187.                  else
  6188.                  begin
  6189.                     --
  6190.                     -- Handling general fixed type column cases
  6191.                     --
  6192.                     if (@num_col = 1)
  6193.                     begin
  6194.                         select @column_string = N'
  6195.                 ' + @cast_str
  6196.                     end
  6197.                     else
  6198.                     begin
  6199.                         select @column_string = N'
  6200.                 + '','' + ' + @cast_str
  6201.                     end
  6202.                     --
  6203.                     -- check if we need to flush the command first
  6204.                     --
  6205.                     if (@fragmentlen + len(@column_string) + @commandlen > 3450)
  6206.                     begin
  6207.                         --
  6208.                         -- send this compensating command first
  6209.                         --
  6210.                         select @cmd = N'
  6211.             from ' + @qualname 
  6212.                         insert into #proctext(procedure_text) values( @cmd )
  6213.                         --
  6214.                         -- script the where clause
  6215.                         --
  6216.                         if (@proctype in (@typeusenew_pk,@typeuseold_pk))
  6217.                         begin
  6218.                             --
  6219.                             -- only PK unique key
  6220.                             --
  6221.                             if (@proctype = @typeuseold_pk)
  6222.                                 exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
  6223.                             else
  6224.                                 exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
  6225.                         end
  6226.                         else
  6227.                         begin
  6228.                             --
  6229.                             -- we are in the cursor for qualifying row
  6230.                             -- 
  6231.                             exec dbo.sp_scriptpkwhereclause @src_objid = @objid
  6232.                                         ,@pkcolumns = @pkcolumns
  6233.                                         ,@prefix = N'@pkc'
  6234.                                         ,@artcolumns = @columns
  6235.                                         ,@mode = 2
  6236.                         end
  6237.                         --
  6238.                         -- Script the compensating send
  6239.                         --
  6240.                         exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
  6241.                         if (@setprefix = 1)
  6242.                             select @setprefix = 0
  6243.  
  6244.                         select @cmd = N'
  6245.             select @cmd = N'' ''' 
  6246.                         insert into #proctext(procedure_text) values( @cmd )
  6247.                         select @commandlen = 0                    
  6248.                     end
  6249.                     --
  6250.                     -- script out the column string
  6251.                     --
  6252.                     insert into #proctext(procedure_text) values( @column_string )
  6253.                     --
  6254.                     -- if we are processing sql_variants, flush the command again
  6255.                     --
  6256.                     if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
  6257.                     begin
  6258.                         --
  6259.                         -- send this compensating command first
  6260.                         --
  6261.                         select @cmd = N'
  6262.             from ' + @qualname 
  6263.                         insert into #proctext(procedure_text) values( @cmd )
  6264.                         --
  6265.                         -- script the where clause
  6266.                         --
  6267.                         if (@proctype in (@typeusenew_pk,@typeuseold_pk))
  6268.                         begin
  6269.                             --
  6270.                             -- only PK unique key
  6271.                             --
  6272.                             if (@proctype = @typeuseold_pk)
  6273.                                 exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
  6274.                             else
  6275.                                 exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
  6276.                         end
  6277.                         else
  6278.                         begin
  6279.                             --
  6280.                             -- we are in the cursor for qualifying row
  6281.                             -- 
  6282.                             exec dbo.sp_scriptpkwhereclause @src_objid = @objid
  6283.                                         ,@pkcolumns = @pkcolumns
  6284.                                         ,@prefix = N'@pkc'
  6285.                                         ,@artcolumns = @columns
  6286.                                         ,@mode = 2
  6287.                         end
  6288.                         --
  6289.                         -- Script the compensating send
  6290.                         --
  6291.                         exec sp_MSscript_compensating_send @pubid, @artid, 1, @setprefix
  6292.                         if (@setprefix = 1)
  6293.                             select @setprefix = 0
  6294.  
  6295.                         select @cmd = N'
  6296.             select @cmd = N'' ''' 
  6297.                         insert into #proctext(procedure_text) values( @cmd )
  6298.                         select @commandlen = 0                    
  6299.                     end
  6300.                     else
  6301.                         select @commandlen = @commandlen + @fragmentlen + len(@column_string)
  6302.                 end
  6303.             end
  6304.         end
  6305.         --
  6306.         -- process the next column
  6307.         --
  6308.         FETCH hCColid INTO @this_col, @collen
  6309.     end
  6310.     CLOSE hCColid
  6311.     DEALLOCATE hCColid
  6312.     --
  6313.     -- Check if we need to flush the command one more time (final)
  6314.     --
  6315.     if (@commandlen > 0)
  6316.     begin
  6317.         --
  6318.         -- send the last fragment of the command
  6319.         --
  6320.         select @cmd = N'
  6321.             from ' + @qualname 
  6322.         insert into #proctext(procedure_text) values( @cmd )
  6323.         --
  6324.         -- script the where clause
  6325.         --
  6326.         if (@proctype in (@typeusenew_pk,@typeuseold_pk))
  6327.         begin
  6328.             --
  6329.             -- only PK unique key
  6330.             --
  6331.             if (@proctype = @typeuseold_pk)
  6332.                 exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0, 'del'
  6333.             else
  6334.                 exec dbo.sp_MSscript_where_clause @objid, @columns, 'new_pk_q', NULL, 0, 'ins'
  6335.         end
  6336.         else
  6337.         begin
  6338.             --
  6339.             -- we are in the cursor for qualifying row
  6340.             -- 
  6341.             exec dbo.sp_scriptpkwhereclause @src_objid = @objid
  6342.                         ,@pkcolumns = @pkcolumns
  6343.                         ,@prefix = N'@pkc'
  6344.                         ,@artcolumns = @columns
  6345.                         ,@mode = 2
  6346.         end
  6347.         --
  6348.         -- Script the compensating send
  6349.         --
  6350.         exec sp_MSscript_compensating_send @pubid, @artid, 0, @setprefix
  6351.     end
  6352.     --
  6353.     -- More scripting for refresh command processing modes
  6354.     --
  6355.     if (@proctype in (@typeuseoldnonpkkeys,@typeusenewnonpkkeys
  6356.                     ,@typeuseoldallkeys,@typeusenewallkeys))
  6357.     begin
  6358.         --
  6359.         -- script the cursor fetch
  6360.         --
  6361.         select @cmd = N'
  6362.             fetch #hccompins into '
  6363.         insert into #proctext(procedure_text) values( @cmd )
  6364.         insert into #proctext(procedure_text) 
  6365.             select procedure_text from @pkfetch order by c1 asc
  6366.         --
  6367.         -- script the cursor close and deallocate
  6368.         --
  6369.         select @cmd = N'
  6370.             end
  6371.             close #hccompins
  6372.             deallocate #hccompins '
  6373.         insert into #proctext(procedure_text) values( @cmd )
  6374.     end
  6375.     --
  6376.     -- all done
  6377.     --
  6378.     return 0
  6379. end
  6380. go
  6381. exec dbo.sp_MS_marksystemobject sp_MSscript_compensating_insert
  6382. go
  6383.  
  6384. --------------------------------------------------------------------------------
  6385. --. sp_MSscript_delete_pubwins
  6386. --------------------------------------------------------------------------------
  6387.  
  6388. if exists (select * from sysobjects
  6389.     where type = 'P' and name = 'sp_MSscript_delete_pubwins')
  6390. drop procedure sp_MSscript_delete_pubwins
  6391. go
  6392. raiserror('Creating procedure sp_MSscript_delete_pubwins', 0,1)
  6393. go
  6394. create procedure sp_MSscript_delete_pubwins 
  6395. (
  6396.     @publication sysname        -- publication name
  6397.     ,@article sysname            -- article name
  6398.     ,@objid int                -- object id
  6399.     ,@columns binary(32)        -- columns replicated
  6400. )
  6401. as
  6402. begin
  6403.     declare @cmd nvarchar(4000)
  6404.             ,@artid int
  6405.             ,@pubid int
  6406.             ,@dest_table sysname
  6407.             ,@dest_owner nvarchar(260)
  6408.             ,@rc           int
  6409.             ,@qualname nvarchar(512)
  6410.             ,@fhasnonpkuniquekeys int
  6411.  
  6412.     --
  6413.     -- initialize the vars we will use
  6414.     --
  6415.     select @pubid = pubid from syspublications where name = @publication
  6416.     select @artid = artid, @dest_table = dest_table, @dest_owner = dest_owner
  6417.     from sysarticles where name = @article and pubid = @pubid
  6418.     select @dest_owner = case when (@dest_owner IS NULL) then N''
  6419.                 else quotename(@dest_owner) + N'.' end
  6420.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  6421.     --
  6422.     -- start scripting
  6423.     --
  6424.     select @cmd = N'
  6425.     if (@execution_mode = @QPubWins)
  6426.     begin
  6427.         '+N'--
  6428.         '+N'-- Publisher wins resolution
  6429.         '+N'-- '
  6430.     insert into #proctext(procedure_text) values( @cmd )
  6431.     --
  6432.     -- declare fetch variables for cursor
  6433.     --
  6434.     exec @rc = sp_scriptpubwinsrefreshcursorvars @objid
  6435.     --
  6436.     -- continue scripting
  6437.     --
  6438.     select @cmd = N'
  6439.  
  6440.         '+N'--
  6441.         '+N'-- --------------------------------------------------------------------
  6442.         '+N'-- Perform refresh(delete+insert) generations next
  6443.         '+N'-- --------------------------------------------------------------------
  6444.         '+N'--
  6445.         
  6446.         '+N'--
  6447.         '+N'-- Generate delete+insert for values of all keys
  6448.         '+N'--
  6449.         if (@cftcase in (30,31))
  6450.         begin'
  6451.     insert into #proctext(procedure_text) values( @cmd )
  6452.     --
  6453.     -- generate delete compensating command for OLD values of all unique keys
  6454.     --
  6455.     select @cmd = N'
  6456.             select @cmd = ''DELETE ' + master.dbo.fn_MSgensqescstr(@dest_owner) collate database_default 
  6457.         + quotename(master.dbo.fn_MSgensqescstr(@dest_table) collate database_default) + N' '' + '
  6458.     insert into #proctext(procedure_text) values( @cmd )
  6459.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @objid
  6460.                 ,@columns = @columns
  6461.                 ,@prefix = N'@c' 
  6462.                 ,@suffix = N'_old'
  6463.                 ,@mode = 4
  6464.     --
  6465.     -- script the sending command
  6466.     --
  6467.     exec sp_MSscript_compensating_send @pubid, @artid, 0, 1
  6468.     --
  6469.     -- script the refresh commands for OLD values of all unique keys
  6470.     --
  6471.     exec @rc = dbo.sp_MSscript_compensating_insert @publication, @article, @objid, @columns, 4, 0
  6472.     if (@rc != 0 or @@error != 0)
  6473.         return 1
  6474.     --
  6475.     -- continue scripting
  6476.     --
  6477.     select @cmd = N'
  6478.         end
  6479.         '+N'--
  6480.         '+N'-- --------------------------------------------------------------------
  6481.         '+N'-- all done for conflict resolution for Publisher Wins policy
  6482.         '+N'-- --------------------------------------------------------------------
  6483.         '+N'--
  6484.     end'
  6485.     insert into #proctext(procedure_text) values( @cmd )
  6486.     --
  6487.     -- all done
  6488.     --
  6489.     return 0        
  6490. end
  6491. go
  6492. exec dbo.sp_MS_marksystemobject sp_MSscript_delete_pubwins
  6493. go
  6494.  
  6495. --------------------------------------------------------------------------------
  6496. --. sp_MSscript_delete_subwins
  6497. --------------------------------------------------------------------------------
  6498.  
  6499. if exists (select * from sysobjects
  6500.     where type = 'P' and name = 'sp_MSscript_delete_subwins')
  6501. drop procedure sp_MSscript_delete_subwins
  6502. go
  6503. raiserror('Creating procedure sp_MSscript_delete_subwins', 0,1)
  6504. go
  6505. create procedure sp_MSscript_delete_subwins 
  6506. (
  6507.     @publication sysname        -- publication name
  6508.     ,@article sysname            -- article name
  6509.     ,@objid int                -- object id
  6510.     ,@columns binary(32)        -- columns replicated
  6511. )
  6512. as
  6513. begin
  6514.     declare @cmd nvarchar(4000)
  6515.             ,@qualname nvarchar(512)
  6516.  
  6517.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  6518.     --
  6519.     -- start scripting
  6520.     --
  6521.     select @cmd = N'
  6522.     if (@execution_mode = @QSubWins)
  6523.     begin
  6524.         '+N'--
  6525.         '+N'-- Subscriber wins resolution
  6526.         '+N'-- 
  6527.         if (@cftcase = 31)
  6528.         begin
  6529.             '+N'--
  6530.             '+N'-- delete row with PK
  6531.             '+N'-- '
  6532.     insert into #proctext(procedure_text) values( @cmd )
  6533.     --
  6534.     -- generate the delete statement
  6535.     --
  6536.     select @cmd = N'
  6537.             delete ' + @qualname 
  6538.     insert into #proctext(procedure_text) values( @cmd )
  6539.     exec dbo.sp_MSscript_where_clause @objid, @columns, 'upd version', NULL, 0
  6540.     --
  6541.     -- continue with scripting
  6542.     --
  6543.     select @cmd = N'            
  6544.         end
  6545.  
  6546.         '+N'--
  6547.         '+N'-- --------------------------------------------------------------------
  6548.         '+N'-- all done for conflict resolution for Subscriber Wins policy
  6549.         '+N'-- --------------------------------------------------------------------
  6550.         '+N'--
  6551.     end'
  6552.     insert into #proctext(procedure_text) values( @cmd )    
  6553.     --
  6554.     -- all done
  6555.     --
  6556.     return 0
  6557. end
  6558. go
  6559. exec dbo.sp_MS_marksystemobject sp_MSscript_delete_subwins
  6560. go
  6561.  
  6562. --------------------------------------------------------------------------------
  6563. --. sp_MSscript_sync_ins_proc
  6564. --------------------------------------------------------------------------------
  6565. if exists (select * from sysobjects
  6566.     where type = 'P' and name = 'sp_MSscript_sync_ins_proc')
  6567. drop procedure sp_MSscript_sync_ins_proc
  6568. go
  6569.  
  6570. raiserror('Creating procedure sp_MSscript_sync_ins_proc', 0,1)
  6571. go
  6572. create procedure sp_MSscript_sync_ins_proc (
  6573.     @publication sysname, 
  6574.     @article     sysname,
  6575.     @procname    sysname)
  6576. as
  6577. BEGIN
  6578.     declare @source_objid int
  6579.             ,@colname sysname
  6580.             ,@indid int
  6581.             ,@cmd          nvarchar(4000)
  6582.             ,@columns      binary(32)
  6583.             ,@outvars      nvarchar(4000)
  6584.             ,@rc           int
  6585.             ,@error_cmd    tinyint
  6586.             ,@identity_insert bit
  6587.             ,@queued_pub bit
  6588.  
  6589.     set nocount on
  6590.     --
  6591.     -- security check
  6592.     --
  6593.     exec @rc = dbo.sp_MSreplcheck_publish
  6594.     if @@error <> 0 or @rc <> 0
  6595.     begin
  6596.         return (1)
  6597.     end
  6598.     --
  6599.     -- Create temp table
  6600.     --
  6601.     create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  6602.     select @queued_pub = allow_queued_tran from syspublications where name = @publication
  6603.  
  6604.     --
  6605.     -- proc definition
  6606.     --
  6607.     exec @rc = dbo.sp_MSscript_beginproc @publication, @article, @procname, @source_objid output, @columns output
  6608.     if @rc = 0
  6609.         return
  6610.  
  6611.     --
  6612.     -- construct parameter list
  6613.     --
  6614.     exec dbo.sp_MSscript_params @source_objid, @columns, null, 1,  @outvars output
  6615.  
  6616.     --
  6617.     -- add other parameters and start body of proc
  6618.     --
  6619.     exec dbo.sp_MSscript_procbodystart @queued_pub
  6620.  
  6621.     --
  6622.     -- script out security check
  6623.     --
  6624.     exec dbo.sp_MSscript_security @publication
  6625.  
  6626.     --
  6627.     -- script the execution mode checks
  6628.     --
  6629.     exec dbo.sp_MSscript_ExecutionMode_stmt @publication, @article, 0
  6630.  
  6631.     --
  6632.     -- script out subscription validation
  6633.     --
  6634.     exec dbo.sp_MSscript_validate_subscription @publication, @article
  6635.  
  6636.     --
  6637.     -- Work around for case where article has 1 col that is not user-modfied (identity, timestamp)
  6638.     -- *** Do we need to check this here - 
  6639.     -- *** we should be checking this when creating subscription
  6640.     -- 
  6641.     exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns
  6642.     if @rc = 1
  6643.         select @error_cmd = 1
  6644.     else
  6645.     begin
  6646.         exec @indid = dbo.sp_MStable_has_unique_index @source_objid 
  6647.         if (@outvars != null and @indid = 0)
  6648.             -- no insert/update allowed if timestamp/identity col and no unique index
  6649.             select @error_cmd = 1
  6650.         else
  6651.             select @error_cmd = 0        
  6652.     end
  6653.  
  6654.     if (@error_cmd = 0)
  6655.     begin
  6656.         -- Continue generation
  6657.     
  6658.         -- Check to see if identity insert must be turned on
  6659.         -- i.e. Does the table has identity that are included in the partition?
  6660.         exec sp_MSis_identity_insert @publication, @article, @identity_insert output
  6661.         --
  6662.         -- script insert statemnt
  6663.         --
  6664.         exec dbo.sp_MSscript_insert_statement @source_objid, @columns, @identity_insert, @queued_pub
  6665.  
  6666.         --
  6667.         -- script queued specific stuff
  6668.         --
  6669.         if (@queued_pub = 1)
  6670.         begin
  6671.             --
  6672.             -- script Conflict finder
  6673.             --
  6674.             exec dbo.sp_MSscriptinsertconflictfinder @publication, @article, @source_objid, @columns
  6675.             --
  6676.             -- script Conflict resolution block for Publisher Wins case
  6677.             --
  6678.             exec dbo.sp_MSscript_insert_pubwins @publication, @article, @source_objid, @columns
  6679.             --
  6680.             -- script Conflict resolution block for Subscriber Wins case
  6681.             --
  6682.             exec dbo.sp_MSscript_insert_subwins @publication, @article, @source_objid, @columns, @identity_insert
  6683.         end
  6684.         
  6685.         --
  6686.         -- script closing 
  6687.         --
  6688.         exec dbo.sp_MSscript_endproc @source_objid, 'ins', @columns, @outvars, @queued_pub
  6689.     end
  6690.     else
  6691.     begin
  6692.         --
  6693.         -- Generate error command and finish
  6694.         --
  6695.         insert into #proctext(procedure_text) values( N'
  6696.     exec sp_MSreplraiserror 20516
  6697. END
  6698. ')
  6699.     end
  6700.                   
  6701.     --
  6702.     -- send fragments to client
  6703.     --
  6704.     select procedure_text from #proctext order by c1 asc
  6705. END
  6706. go
  6707. EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_ins_proc
  6708. GO
  6709. grant execute on dbo.sp_MSscript_sync_ins_proc  to public
  6710. go
  6711.  
  6712. --------------------------------------------------------------------------------
  6713. --. sp_MSscript_sync_upd_proc
  6714. --------------------------------------------------------------------------------
  6715.  
  6716. if exists (select * from sysobjects
  6717.     where type = 'P' and name = 'sp_MSscript_sync_upd_proc')
  6718. drop procedure sp_MSscript_sync_upd_proc
  6719. go
  6720. raiserror('Creating procedure sp_MSscript_sync_upd_proc', 0,1)
  6721. go
  6722. create procedure sp_MSscript_sync_upd_proc (
  6723.     @publication sysname, 
  6724.     @article     sysname,
  6725.     @procname    sysname)
  6726. as
  6727. BEGIN
  6728.     declare @source_objid int
  6729.             ,@colname sysname
  6730.             ,@indid int
  6731.             ,@cmd          nvarchar(4000)
  6732.             ,@columns      binary(32)
  6733.             ,@outvars      nvarchar(4000)
  6734.             ,@rc           int
  6735.             ,@error_cmd    tinyint
  6736.             ,@identity_insert bit
  6737.             ,@queued_pub bit
  6738.  
  6739.     set nocount on
  6740.     --
  6741.     -- security check
  6742.     --
  6743.     exec @rc = dbo.sp_MSreplcheck_publish
  6744.     if @@error <> 0 or @rc <> 0
  6745.     begin
  6746.         return (1)
  6747.     end
  6748.     --
  6749.     -- Create temp table
  6750.     --
  6751.     create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  6752.     select @queued_pub = allow_queued_tran from syspublications where name = @publication
  6753.  
  6754.     --
  6755.     -- proc definition
  6756.     --
  6757.     exec @rc = dbo.sp_MSscript_beginproc @publication, @article, @procname, @source_objid output, @columns output
  6758.     if @rc = 0
  6759.         return
  6760.  
  6761.     --
  6762.     -- construct parameter list
  6763.     -- Script bitmap parameter
  6764.     --
  6765.     exec dbo.sp_MSscript_params @source_objid, @columns, null, 1,  @outvars output
  6766.     insert into #proctext(procedure_text) values( N',')
  6767.     exec dbo.sp_MSscript_params @source_objid, @columns, N'_old', 0, null
  6768.     insert into #proctext(procedure_text) values( N'
  6769.     ,@bitmap varbinary(4000)')
  6770.  
  6771.     --
  6772.     -- add other parameters and start body of proc
  6773.     --
  6774.     exec dbo.sp_MSscript_procbodystart @queued_pub 
  6775.  
  6776.     --
  6777.     -- script out security check
  6778.     --
  6779.     exec dbo.sp_MSscript_security @publication
  6780.  
  6781.     --
  6782.     -- script the execution mode checks
  6783.     --
  6784.     exec dbo.sp_MSscript_ExecutionMode_stmt @publication, @article, 2
  6785.  
  6786.     --
  6787.     -- script out subscription validation
  6788.     --
  6789.     exec dbo.sp_MSscript_validate_subscription @publication, @article
  6790.  
  6791.     --
  6792.     -- Work around for case where article has 1 col that is not user-modfied (identity, timestamp)
  6793.     -- *** Do we need to check this here - 
  6794.     -- *** we should be checking this when creating subscription
  6795.     -- 
  6796.     exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns
  6797.     if @rc = 1
  6798.         select @error_cmd = 1
  6799.     else
  6800.     begin
  6801.         exec @indid = dbo.sp_MStable_has_unique_index @source_objid 
  6802.         if (@outvars != null and @indid = 0)
  6803.             -- no insert/update allowed if timestamp/identity col and no unique index
  6804.             select @error_cmd = 1
  6805.         else
  6806.             select @error_cmd = 0        
  6807.     end
  6808.  
  6809.     if (@error_cmd = 0)
  6810.     begin
  6811.         -- Continue generation
  6812.         
  6813.         --
  6814.         -- script update statemnt
  6815.         --
  6816.         exec dbo.sp_MSscript_update_statement @publication, @article, @source_objid, @columns, @queued_pub
  6817.  
  6818.         --
  6819.         -- script queued specific stuff
  6820.         --
  6821.         if (@queued_pub = 1)
  6822.         begin
  6823.             -- Check to see if identity insert must be turned on
  6824.             -- i.e. Does the table has identity that are included in the partition?
  6825.             exec sp_MSis_identity_insert @publication, @article, @identity_insert output
  6826.             --
  6827.             -- script the conflict resolution logic common to all resolution policies
  6828.             --
  6829.             exec dbo.sp_MSscriptupdateconflictfinder @publication, @article, @source_objid, @columns
  6830.             --
  6831.             -- script Conflict resolution block for Publisher Wins case
  6832.             --
  6833.             exec dbo.sp_MSscript_update_pubwins @publication, @article, @source_objid, @columns
  6834.             --
  6835.             -- script Conflict resolution block for Subscriber Wins case
  6836.             --
  6837.             exec dbo.sp_MSscript_update_subwins @publication, @article, @source_objid, @columns, @identity_insert
  6838.         end
  6839.  
  6840.         --
  6841.         -- script closing 
  6842.         --
  6843.         exec dbo.sp_MSscript_endproc @source_objid, 'upd', @columns, @outvars, @queued_pub
  6844.     end
  6845.     else
  6846.     begin
  6847.         --
  6848.         -- Generate error command and finish
  6849.         --
  6850.         insert into #proctext(procedure_text) values( N'
  6851.     exec sp_MSreplraiserror 20516
  6852. END
  6853. ')
  6854.     end
  6855.                   
  6856.     --
  6857.     -- send fragments to client
  6858.     --
  6859.     select procedure_text from #proctext order by c1 asc
  6860. END
  6861. go
  6862. exec dbo.sp_MS_marksystemobject sp_MSscript_sync_upd_proc
  6863. GO
  6864. grant execute on dbo.sp_MSscript_sync_upd_proc  to public
  6865. go
  6866.  
  6867. --------------------------------------------------------------------------------
  6868. --. sp_MSscript_sync_del_proc
  6869. --------------------------------------------------------------------------------
  6870.  
  6871. if exists (select * from sysobjects
  6872.     where type = 'P' and name = 'sp_MSscript_sync_del_proc')
  6873. drop procedure sp_MSscript_sync_del_proc
  6874. go
  6875. raiserror('Creating procedure sp_MSscript_sync_del_proc', 0,1)
  6876. go
  6877. create procedure sp_MSscript_sync_del_proc (
  6878.     @publication sysname, 
  6879.     @article     sysname,
  6880.     @procname    sysname)
  6881. as
  6882. BEGIN
  6883.     declare @source_objid int
  6884.     declare @colname sysname
  6885.     declare @indid int
  6886.     declare @cmd          nvarchar(4000)
  6887.     declare @columns      binary(32)
  6888.     declare @outvars      nvarchar(4000)
  6889.     declare @rc           int
  6890.     declare @error_cmd    tinyint
  6891.     declare @queued_pub bit
  6892.  
  6893.     set nocount on
  6894.     --
  6895.     -- security check
  6896.     --
  6897.     exec @rc = dbo.sp_MSreplcheck_publish
  6898.     if @@error <> 0 or @rc <> 0
  6899.     begin
  6900.         return (1)
  6901.     end
  6902.     --
  6903.     -- Create temp table
  6904.     --
  6905.     create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  6906.     select @queued_pub = allow_queued_tran from syspublications where name = @publication
  6907.  
  6908.     --
  6909.     -- proc definition
  6910.     --
  6911.     exec @rc = dbo.sp_MSscript_beginproc @publication, @article, @procname, @source_objid output, @columns output
  6912.     if @rc = 0
  6913.         return
  6914.  
  6915.     --
  6916.     -- construct parameter list
  6917.     --
  6918.     exec dbo.sp_MSscript_params @source_objid, @columns, N'_old', 0, null
  6919.  
  6920.     --
  6921.     -- add other parameters and start body of proc
  6922.     --
  6923.     exec dbo.sp_MSscript_procbodystart @queued_pub 
  6924.  
  6925.     --
  6926.     -- script out security check
  6927.     --
  6928.     exec dbo.sp_MSscript_security @publication
  6929.  
  6930.     --
  6931.     -- script the execution mode checks
  6932.     --
  6933.     exec dbo.sp_MSscript_ExecutionMode_stmt @publication, @article, 1
  6934.  
  6935.     --
  6936.     -- script out subscription validation
  6937.     --
  6938.     exec dbo.sp_MSscript_validate_subscription @publication, @article
  6939.  
  6940.     --
  6941.     -- Work around for case where article has 1 col that is not user-modfied (identity, timestamp)
  6942.     -- *** Do we need to check this here - 
  6943.     -- *** we should be checking this when creating subscription
  6944.     -- 
  6945.     exec @rc = dbo.sp_MStable_not_modifiable @source_objid, @columns
  6946.     if @rc = 1
  6947.         select @error_cmd = 1
  6948.     else
  6949.     begin
  6950.         exec @indid = dbo.sp_MStable_has_unique_index @source_objid 
  6951.         if (@outvars != null and @indid = 0)
  6952.             -- no insert/update allowed if timestamp/identity col and no unique index
  6953.             select @error_cmd = 1
  6954.         else
  6955.             select @error_cmd = 0        
  6956.     end
  6957.  
  6958.     if (@error_cmd = 0)
  6959.     begin
  6960.         -- Continue generation
  6961.         
  6962.         --
  6963.         -- script delete statemnt
  6964.         --
  6965.         exec dbo.sp_MSscript_delete_statement @publication, @article, @source_objid, @columns, @queued_pub
  6966.  
  6967.         --
  6968.         -- script queued specific stuff
  6969.         --
  6970.         if (@queued_pub = 1)
  6971.         begin
  6972.             --
  6973.             -- script the conflict resolution logic common to all resolution policies
  6974.             --
  6975.             exec sp_MSscriptdelconflictfinder @publication, @article, @source_objid, @columns
  6976.             --
  6977.             -- script Conflict resolution block for Publisher Wins case
  6978.             --
  6979.             exec dbo.sp_MSscript_delete_pubwins @publication, @article, @source_objid, @columns
  6980.             --
  6981.             -- script Conflict resolution block for Subscriber Wins case
  6982.             --
  6983.             exec dbo.sp_MSscript_delete_subwins @publication, @article, @source_objid, @columns
  6984.         end
  6985.         
  6986.         --
  6987.         -- script closing 
  6988.         --
  6989.         exec dbo.sp_MSscript_endproc @source_objid, 'del', @columns, @outvars, @queued_pub
  6990.     end
  6991.     else
  6992.     begin
  6993.         --
  6994.         -- Generate error command and finish
  6995.         --
  6996.         insert into #proctext(procedure_text) values( N'
  6997.     exec sp_MSreplraiserror 20516
  6998. END
  6999. ')
  7000.     end
  7001.                   
  7002.     --
  7003.     -- send fragments to client
  7004.     --
  7005.     select procedure_text from #proctext order by c1 asc
  7006.  
  7007. END
  7008. go
  7009. EXEC dbo.sp_MS_marksystemobject sp_MSscript_sync_del_proc
  7010. GO
  7011. grant execute on dbo.sp_MSscript_sync_del_proc  to public
  7012. go
  7013.  
  7014. --------------------------------------------------------------------------------
  7015. --. sp_MSscript_endproc
  7016. --------------------------------------------------------------------------------
  7017.  
  7018. if exists (select * from sysobjects
  7019.     where type = 'P' and name = 'sp_MSscript_endproc')
  7020. drop procedure sp_MSscript_endproc
  7021. go
  7022. raiserror('Creating procedure sp_MSscript_endproc', 0,1)
  7023. go
  7024. create procedure sp_MSscript_endproc (
  7025.     @objid int, 
  7026.     @op_type varchar(3) = 'ins', -- 'ins', 'upd', 'del'
  7027.     @columns binary(32),
  7028.     @outvars nvarchar(4000),
  7029.     @queued_pub bit = 0
  7030. )
  7031. as
  7032. BEGIN
  7033.     declare @cmd nvarchar(4000)
  7034.     declare @qualname nvarchar(512)
  7035.  
  7036.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  7037.  
  7038.     --
  7039.     -- start scripting
  7040.     --
  7041.     select @cmd = N'
  7042.     ' + N'--
  7043.     ' + N'-- decide the return code
  7044.     ' + N'--
  7045.     if (@execution_mode = @immediate)
  7046.     begin
  7047.         if @error != 0
  7048.               return -1
  7049.         -- Return special code to indicate the subscriber row needs to be
  7050.         -- refreshed.
  7051.         if @rowcount = 0
  7052.               return 5
  7053.     end'
  7054.     insert into #proctext(procedure_text) values(@cmd)
  7055.  
  7056.     --
  7057.     -- operation specific stuff
  7058.     --
  7059.     if (@queued_pub = 1)
  7060.     begin
  7061.         if (@op_type = 'ins')
  7062.         begin
  7063.             select @cmd = N'
  7064.     if (@execution_mode = @QFirstPass)
  7065.     begin
  7066.         if (@rowcount = 0)
  7067.         begin
  7068.             if (@error in (547, 2601, 2627))
  7069.                 return 2 -- insert conflict
  7070.             else
  7071.                 return -1 -- error
  7072.         end
  7073.     end'
  7074.         end
  7075.         else if (@op_type = 'upd')
  7076.         begin
  7077.             select @cmd = N'
  7078.     if (@execution_mode = @QFirstPass)
  7079.     begin
  7080.         if (@rowcount = 0)
  7081.         begin
  7082.             if (@error in (0, 547, 2601, 2627))
  7083.                 return 1 -- update conflict
  7084.             else
  7085.                 return -1 -- error
  7086.         end
  7087.     end'
  7088.         end
  7089.         else if (@op_type = 'del')
  7090.         begin
  7091.             select @cmd = N'
  7092.     if (@execution_mode = @QFirstPass)
  7093.     begin
  7094.         if (@rowcount = 0)
  7095.         begin
  7096.             if (@error in (0, 547))
  7097.                 return 3 -- delete conflict
  7098.             else
  7099.                 return -1 -- error
  7100.         end
  7101.     end'
  7102.         end
  7103.         insert into #proctext(procedure_text) values(@cmd)
  7104.         
  7105.         --
  7106.         -- continue with scripting
  7107.         --
  7108.         select @cmd = N'
  7109.     
  7110.     if (@execution_mode in (@QPubWins, @QSubWins))
  7111.     begin        
  7112.         if (@@error != 0 or @retcode != 0)
  7113.             return -1 -- error
  7114.     end
  7115.     '
  7116.         insert into #proctext(procedure_text) values(@cmd)
  7117.     end
  7118.  
  7119.     --
  7120.     -- if we have output vars to assign do it now
  7121.     --
  7122.     if (@outvars is not null)
  7123.     begin   
  7124.         if @op_type = 'upd'
  7125.         begin
  7126.             --
  7127.             -- Script out pk var assigment that used in sp_MSscript_where_clause
  7128.             --
  7129.             exec dbo.sp_MSscript_pkvar_assignment @objid, @columns, 1, null, null, null, @queued_pub
  7130.             insert into #proctext(procedure_text) values(N'
  7131.     ')
  7132.         end
  7133.  
  7134.         select @cmd = N'
  7135.     select ' + @outvars + N'
  7136.     from ' + @qualname 
  7137.         insert into #proctext(procedure_text) values( @cmd)
  7138.         insert into #proctext(procedure_text) values( N'
  7139.     ')
  7140.     
  7141.         if (@op_type = 'ins')
  7142.             exec dbo.sp_MSscript_where_clause @objid, @columns, 'new pk', null, 4
  7143.         else if (@op_type = 'upd')
  7144.             exec dbo.sp_MSscript_where_clause @objid, @columns, 'old pk', null, 4
  7145.     end
  7146.  
  7147.     --
  7148.     -- Final part of the proc
  7149.     --
  7150.     select @cmd = N'
  7151.     
  7152.     ' + N'--
  7153.     ' + N'-- past all checks
  7154.     ' + N'--
  7155.     return 0
  7156. END
  7157. '
  7158.     insert into #proctext(procedure_text) values(@cmd)
  7159.     
  7160.     --
  7161.     -- all done
  7162.     --
  7163.     return 0
  7164. END
  7165. go
  7166. exec dbo.sp_MS_marksystemobject sp_MSscript_endproc
  7167. go
  7168. grant execute on dbo.sp_MSscript_endproc  to public
  7169. go
  7170.  
  7171. --------------------------------------------------------------------------------
  7172. --. sp_scriptinsproc
  7173. --------------------------------------------------------------------------------
  7174.  
  7175. if exists (select * from sysobjects
  7176.     where type = 'P' and name = 'sp_scriptinsproc')
  7177. drop procedure sp_scriptinsproc
  7178. go
  7179. raiserror('Creating procedure sp_scriptinsproc', 0,1)
  7180. go
  7181. create procedure sp_scriptinsproc (
  7182.     @artid int)
  7183. as
  7184. BEGIN
  7185. declare @cmd          nvarchar(4000)
  7186.         ,@dest_owner   nvarchar(255)
  7187.         ,@dest_tabname sysname
  7188.         ,@src_objid    int
  7189.         ,@columns      binary(32)
  7190.         ,@ins_cmd      nvarchar(255)
  7191.         ,@dest_proc    sysname
  7192.         ,@this_col     int
  7193.         ,@art_col      int
  7194.         ,@isset        int
  7195.         ,@pubid          int
  7196.  
  7197.         ,@identity_insert bit
  7198.         ,@rc int
  7199.         ,@colname sysname
  7200.         ,@ccoltype     sysname
  7201.         ,@typestring   nvarchar(255)
  7202.         ,@spacer       nvarchar(1)
  7203.         ,@queued_check bit
  7204.         ,@column_string nvarchar(4000)
  7205.         ,@var_string nvarchar(4000)
  7206.  
  7207. set nocount on
  7208. --
  7209. -- security check
  7210. --
  7211. exec @rc = dbo.sp_MSreplcheck_publish
  7212. if @@error <> 0 or @rc <> 0
  7213. begin
  7214.     return (1)
  7215. end
  7216.  
  7217. if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
  7218. begin
  7219.     raiserror (14155, 16, 1 )
  7220.     return 1
  7221. end
  7222.  
  7223. -------- create temp table for command fragments and insert column list
  7224.  
  7225. create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  7226. create table #collisttab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  7227.  
  7228. -------- get sysarticles information
  7229.  
  7230. select @dest_owner = dest_owner, @dest_tabname = dest_table, 
  7231.        @src_objid = objid, @columns = columns, @ins_cmd = ins_cmd,
  7232.        @pubid = pubid
  7233. from sysarticles
  7234. where artid = @artid
  7235.  
  7236. -- Check to see if identity insert must be turned on
  7237. -- i.e. Does the table has identity that are included in the partition?
  7238. exec sp_MSis_identity_insert null, null, @identity_insert output, @artid
  7239. --
  7240.  
  7241. if @dest_owner is not null
  7242. begin
  7243.     select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
  7244. end
  7245. else
  7246. begin
  7247.     select @dest_owner = N''
  7248. end
  7249.  
  7250. -- Check if this is a queued publication
  7251. select @queued_check = ISNULL(allow_queued_tran, 0) 
  7252. from syspublications
  7253. where pubid = @pubid
  7254.  
  7255. -------- get dest proc name
  7256.  
  7257. if( 1 != charindex( N'CALL', upper(@ins_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @ins_cmd is null
  7258. begin
  7259.     raiserror (14156, 16, 1 )
  7260.     return 1
  7261. end
  7262.  
  7263. select @dest_proc = substring( @ins_cmd, 6, len( @ins_cmd ) - 4 )
  7264. select @cmd = N'if exists (select * from sysobjects where type = ''P'' and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
  7265. insert into #proctext(procedure_text) values( @cmd )
  7266. insert into #proctext(procedure_text) values( N'go' )
  7267. select @cmd = N'create procedure ' + QUOTENAME(@dest_proc)
  7268.  
  7269. -------- construct parameter list
  7270.  
  7271.  
  7272. select @art_col = 1
  7273. select @spacer = N' '
  7274.  
  7275. DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  7276. select colid from syscolumns where id = @src_objid order by colid asc
  7277.  
  7278. OPEN hCColid
  7279.  
  7280. FETCH hCColid INTO @this_col
  7281.  
  7282. WHILE (@@fetch_status <> -1)
  7283. begin
  7284.    exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
  7285.    if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
  7286.    begin
  7287.         if len( @cmd ) > 3000
  7288.         begin
  7289.         insert into #proctext(procedure_text) values( @cmd )
  7290.             select @cmd = N''
  7291.         end
  7292.  
  7293.         exec dbo.sp_gettypestring @src_objid, @this_col, @typestring OUTPUT
  7294.         select @cmd = @cmd + @spacer + N'@c' + convert( nvarchar, @art_col ) + N' ' + @typestring 
  7295.         select @art_col = @art_col + 1
  7296.         select @spacer = N','
  7297.    end
  7298.    FETCH hCColid INTO @this_col
  7299. end
  7300.  
  7301. CLOSE hCColid
  7302. DEALLOCATE hCColid
  7303.  
  7304. -- save off cmd fragment
  7305.  
  7306. insert into #proctext(procedure_text) values( @cmd )
  7307.  
  7308. select @cmd = N'
  7309. AS
  7310. BEGIN
  7311. '
  7312. insert into #proctext(procedure_text) values( @cmd )
  7313.  
  7314. ------- construct proc body
  7315.  
  7316. -- Generate strings for col names and variables
  7317. select @art_col = 0
  7318. select @spacer = N' '
  7319.  
  7320. DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  7321. select colid from syscolumns where id = @src_objid order by colid asc
  7322.  
  7323. OPEN hCColid
  7324.  
  7325. FETCH hCColid INTO @this_col
  7326.  
  7327. WHILE (@@fetch_status <> -1)
  7328. begin
  7329.     exec @rc = dbo.sp_MSget_colinfo @src_objid, @this_col, @columns, 1, @colname output, @ccoltype output
  7330.     if @rc = 0  and EXISTS (select name from syscolumns where id=@src_objid and colid=@this_col and iscomputed<>1)
  7331.     begin
  7332.         select @art_col = @art_col + 1
  7333.         if (@art_col = 1)
  7334.         begin
  7335.             select @column_string = QUOTENAME(@colname)
  7336.             select @var_string = N'@c' + cast(@art_col as nvarchar(4))
  7337.         end
  7338.         else
  7339.         begin
  7340.             select @column_string = @column_string + N', ' + QUOTENAME(@colname)
  7341.             select @var_string = @var_string + N', @c' + cast(@art_col as nvarchar(4))
  7342.         end
  7343.  
  7344.         -- transfer column list string to table if too large
  7345.         if (len(@column_string) > 3000)
  7346.         begin
  7347.             insert into #collisttab(procedure_text) values( @column_string )
  7348.             select @column_string = ' '
  7349.         end
  7350.     end
  7351.     FETCH hCColid INTO @this_col
  7352. end
  7353.  
  7354. CLOSE hCColid
  7355. DEALLOCATE hCColid
  7356.  
  7357. -- insert the remaining strings for column list and where clause
  7358. insert into #collisttab(procedure_text) values( @column_string )
  7359.  
  7360. --
  7361. -- If we are a part of queued publication then 
  7362. -- insert only if PK or other unique key(s) do not exist
  7363. --
  7364. if (@queued_check = 1)
  7365. begin
  7366.     select @cmd = N'
  7367. if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' '
  7368.     insert into #proctext(procedure_text) values( @cmd )
  7369.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid
  7370.                                                         ,@columns = @columns
  7371.                                                         ,@prefix = '@c' 
  7372.                                                         ,@mode = 1
  7373.     if (@@error != 0 or @rc != 0)
  7374.         return 1
  7375.     select @cmd = N')
  7376. BEGIN'
  7377.     insert into #proctext(procedure_text) values( @cmd )
  7378. end
  7379.  
  7380. -- set identity_insert on
  7381. if @identity_insert = 1
  7382. begin
  7383.     select @cmd = N'
  7384.     set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' on'
  7385.     insert into #proctext(procedure_text) values( @cmd )
  7386. end
  7387.  
  7388. --
  7389. -- prepare the insert statement now
  7390. --
  7391. select @cmd = N'
  7392. insert into ' +  @dest_owner + QUOTENAME(@dest_tabname)  + N'( '
  7393. insert into #proctext(procedure_text) values( @cmd )
  7394. insert into #proctext(procedure_text) 
  7395.     select procedure_text from #collisttab order by c1 asc
  7396. select @cmd = N' )'
  7397. insert into #proctext(procedure_text) values( @cmd )
  7398. if @art_col > 0
  7399. begin
  7400.     select @cmd = N'
  7401. values ( '
  7402.     insert into #proctext(procedure_text) values( @cmd )
  7403.     insert into #proctext(procedure_text) values( @var_string )
  7404.     select @cmd = N' )
  7405. '
  7406.     insert into #proctext(procedure_text) values( @cmd )
  7407. end
  7408.  
  7409. -- set identity_insert off
  7410. if @identity_insert = 1
  7411. begin
  7412.     select @cmd = N'
  7413.     set identity_insert ' + @dest_owner + QUOTENAME(@dest_tabname) + ' off'
  7414.     insert into #proctext(procedure_text) values( @cmd )
  7415. end
  7416.  
  7417. --
  7418. -- If we are a part of queued publication then 
  7419. -- add the block delimiter
  7420. --
  7421. drop table #collisttab
  7422. if (@queued_check = 1)
  7423. begin
  7424.     select @cmd = N'
  7425. END
  7426. END'
  7427. end
  7428. else
  7429.     select @cmd = N'
  7430. END'
  7431. insert into #proctext(procedure_text) values( @cmd )
  7432.  
  7433. -- send fragements to client
  7434.  
  7435. select procedure_text from #proctext order by c1 asc
  7436. END
  7437. go
  7438. EXEC dbo.sp_MS_marksystemobject sp_scriptinsproc
  7439. GO
  7440. grant exec on dbo.sp_scriptinsproc to public
  7441. go
  7442.  
  7443. --------------------------------------------------------------------------------
  7444. --. sp_scriptxupdproc
  7445. --------------------------------------------------------------------------------
  7446.  
  7447. if exists (select * from sysobjects
  7448.     where type = 'P' and name = 'sp_scriptxupdproc')
  7449. drop procedure sp_scriptxupdproc
  7450. go
  7451. raiserror('Creating procedure sp_scriptxupdproc', 0,1)
  7452. go
  7453. create procedure sp_scriptxupdproc @artid int
  7454. as
  7455. BEGIN
  7456. declare @cmd          nvarchar(4000),
  7457.         @dest_owner   nvarchar(255),
  7458.         @dest_tabname sysname,
  7459.         @src_objid    int,
  7460.         @artcolumns   binary(32),
  7461.         @pkcolumns    binary(32),
  7462.         @upd_cmd      nvarchar(255),
  7463.         @dest_proc    sysname,
  7464.         @this_col     int,
  7465.         @art_col      int,
  7466.         --@pkart_col    int,
  7467.         @isset        int,
  7468.         @rc int,
  7469.         @fhasnonpkuniquekeys int,
  7470.         @pkcomputed   int,
  7471.         @typestring   nvarchar(255),
  7472.         @spacer       nvarchar(10),
  7473.         @pubid          int, 
  7474.         @param_count  int
  7475.         ,@queued_check bit, @exists_else bit
  7476.         ,@qwhere_string nvarchar(4000)
  7477.  
  7478. set nocount on
  7479. --
  7480. -- security check
  7481. --
  7482. exec @rc = dbo.sp_MSreplcheck_publish
  7483. if @@error <> 0 or @rc <> 0
  7484. begin
  7485.     return (1)
  7486. end
  7487. if not exists( select * from sysarticles where artid = @artid AND (type & 1) = 1 )
  7488. begin
  7489.     raiserror (14155, 16, 1 )
  7490.     return 1
  7491. end
  7492.  
  7493. select @exists_else = 0
  7494.          ,@fhasnonpkuniquekeys = 0
  7495.  
  7496. -------- create temp table for command fragments
  7497.  
  7498. create table #proctext ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  7499.  
  7500. -------- get sysarticles information
  7501.  
  7502. select @pubid = pubid, @dest_owner = dest_owner, @dest_tabname = dest_table, 
  7503.        @src_objid = objid, @artcolumns = columns, @upd_cmd = upd_cmd
  7504. from sysarticles
  7505. where artid = @artid
  7506.  
  7507. if @dest_owner is not null
  7508. begin
  7509.     select @dest_owner = QUOTENAME( @dest_owner ) + N'.'
  7510. end
  7511. else
  7512. begin
  7513.     select @dest_owner = N''
  7514. end
  7515.  
  7516. -- Check if this is a queued publication
  7517. select @queued_check = ISNULL(allow_queued_tran, 0) 
  7518. from syspublications
  7519. where pubid = @pubid
  7520.  
  7521. -------- get dest proc name
  7522.  
  7523. if( 1 != charindex( N'XCALL', upper(@upd_cmd collate SQL_Latin1_General_CP1_CS_AS) ) ) or @upd_cmd is null
  7524. begin
  7525.     raiserror (14156, 16, 1 )
  7526.     return 1
  7527. end
  7528.  
  7529. declare @keep_identity bit
  7530. if exists (select * from syspublications where pubid = @pubid and
  7531.     allow_queued_tran = 1) and OBJECTPROPERTY(@src_objid, 'tablehasidentity') = 1
  7532.     select @keep_identity = 1
  7533. else
  7534.     select @keep_identity = 0
  7535.  
  7536. select @dest_proc = substring( @upd_cmd, 7, len( @upd_cmd ) - 5 )
  7537. select @cmd = N'if exists (select * from sysobjects where type = ''P''  and name = ''' + replace(@dest_proc, N'''', N'''''') + N''')  drop proc ' + QUOTENAME(@dest_proc)
  7538. insert into #proctext(procedure_text) values( @cmd )
  7539. insert into #proctext(procedure_text) values( N'go' )
  7540. insert into #proctext( procedure_text ) values (  N'create procedure ' + QUOTENAME(@dest_proc) + N' ')
  7541.  
  7542. -------- construct parameter list
  7543.  
  7544. exec dbo.sp_getarticlepkcolbitmap @src_objid, @pkcolumns output
  7545.  
  7546. -- Send null as @pkcolumns. We don't need pk parameters.
  7547. exec dbo.sp_scriptupdateparams @src_objid, @artcolumns, NULL, @param_count output
  7548.  
  7549. insert into #proctext(procedure_text) values ( N'as' )
  7550.  
  7551. --
  7552. -- If we are a part of queued publication 
  7553. --
  7554. if (@queued_check = 1)
  7555. begin
  7556.     --
  7557.     -- Check if we have non PK unique keys
  7558.     --
  7559.     exec @fhasnonpkuniquekeys = dbo.sp_repltablehasnonpkuniquekey @tabid = @src_objid
  7560.     if (@fhasnonpkuniquekeys = 1)
  7561.     begin
  7562.         --
  7563.         -- There are non PK unique keys
  7564.         -- update only if updated values of non PK unique key(s) do not exist
  7565.         --
  7566.         select @cmd = N'
  7567. if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' '
  7568.         insert into #proctext(procedure_text) values( @cmd )
  7569.         exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid
  7570.                                                         ,@columns = @artcolumns
  7571.                                                         ,@prefix = '@c' 
  7572.                                                         ,@mode = 2
  7573.                                                         ,@paramcount = @param_count
  7574.         if (@@error != 0 or @rc != 0)
  7575.             return 1
  7576.         select @cmd = N')
  7577. begin'
  7578.         insert into #proctext(procedure_text) values( @cmd )
  7579.     end
  7580. end
  7581.  
  7582. -------- now create the update statement
  7583.  
  7584. -- construct test to see if pk has changed 
  7585. -- only do this if the article has columns not included in the pk
  7586.  
  7587. exec @pkcomputed = sp_MSareallcolumnscomputed @src_objid, @pkcolumns
  7588.  
  7589. declare @pk_is_identity bit
  7590. select @pk_is_identity = 0
  7591.  
  7592. if @artcolumns != @pkcolumns and @pkcomputed = 0
  7593. begin
  7594.     select @cmd = N'if'
  7595.  
  7596.     select @art_col = 1
  7597.     --select @pkart_col = 1
  7598.     select @spacer = ' '
  7599.  
  7600.     DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  7601.     select colid from syscolumns where id = @src_objid order by colid asc
  7602.  
  7603.     OPEN hCColid
  7604.  
  7605.     FETCH hCColid INTO @this_col
  7606.  
  7607.     select @pk_is_identity = 1
  7608.     WHILE (@@fetch_status <> -1)
  7609.     begin
  7610.         exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
  7611.         if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
  7612.         begin
  7613.             exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
  7614.             if @isset != 0
  7615.             begin
  7616.                 if not (@keep_identity = 1 and 
  7617.                     columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
  7618.                 begin
  7619.                     select @pk_is_identity = 0
  7620.                     select @cmd = @cmd + @spacer + N'@c'+convert( nvarchar, @art_col + @param_count/2) + 
  7621.                         N' = @c' + convert( nvarchar, @art_col ) 
  7622.                     select @spacer = N' and '
  7623.                     --select @pkart_col = @pkart_col + 1
  7624.                     if len( @cmd ) > 3000
  7625.                     begin
  7626.                     insert into #proctext(procedure_text) values( @cmd )
  7627.                         select @cmd = N''
  7628.                     end
  7629.                 end
  7630.             end
  7631.             select @art_col = @art_col + 1
  7632.         end
  7633.         FETCH hCColid INTO @this_col
  7634.     end
  7635.  
  7636.     CLOSE hCColid
  7637.     DEALLOCATE hCColid
  7638.  
  7639.     if @pk_is_identity = 0
  7640.     begin
  7641.         insert into #proctext(procedure_text) values( @cmd )
  7642.  
  7643.         insert into #proctext(procedure_text) values( N'begin' )
  7644.  
  7645.         -- construct update if pk hasn't changed
  7646.         -- We know that there would be a least one column for the update below, even if
  7647.         -- the columns outside the pk are identity or timestamp. Since identity and timestamp
  7648.         -- will be mapped off unless it is queued tran. In that case, we have 'msrepl_tran_version'
  7649.         select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'
  7650.  
  7651.         -- create SET clause
  7652.  
  7653.         select @art_col = 1
  7654.         select @spacer = N' '
  7655.  
  7656.         DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  7657.         select colid from syscolumns where id = @src_objid order by colid asc
  7658.  
  7659.         OPEN hCColid
  7660.  
  7661.         FETCH hCColid INTO @this_col
  7662.         WHILE (@@fetch_status <> -1)
  7663.         begin
  7664.             exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
  7665.             if @isset != 0  and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
  7666.             begin
  7667.                 exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
  7668.                 if @isset = 0
  7669.                 begin
  7670.                     if not (@keep_identity = 1 and 
  7671.                         columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
  7672.                     begin
  7673.                         select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + 
  7674.                             N' = @c' + convert( nvarchar, @art_col + @param_count/2) 
  7675.                         select @spacer = N','
  7676.  
  7677.                         if len( @cmd ) > 3000
  7678.                         begin
  7679.                             insert into #proctext(procedure_text) values( @cmd )
  7680.                             select @cmd = N''
  7681.                         end
  7682.  
  7683.                         --
  7684.                         -- Queued processing:if this is the row version column : need to add to where clause
  7685.                         --
  7686.                         if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
  7687.                             select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )                        
  7688.                     end
  7689.                 end
  7690.                 select @art_col = @art_col + 1
  7691.             end
  7692.             FETCH hCColid INTO @this_col
  7693.         end
  7694.         CLOSE hCColid
  7695.         DEALLOCATE hCColid
  7696.  
  7697.         insert into #proctext(procedure_text) values( @cmd )
  7698.  
  7699.         exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns
  7700.         if (@queued_check = 1)
  7701.             insert into #proctext(procedure_text) values( @qwhere_string )
  7702.         else
  7703.             exec dbo.sp_MSscript_missing_row_check
  7704.  
  7705.         insert into #proctext(procedure_text) values( N'end' )
  7706.         insert into #proctext(procedure_text) values( N'else' )
  7707.         insert into #proctext(procedure_text) values( N'begin' )
  7708.  
  7709.         select @exists_else = 1
  7710.  
  7711.     end
  7712. end -- end if artcols != pkcols
  7713.  
  7714. --
  7715. -- If we are a part of queued publication then 
  7716. -- update only if updated value of PK does not exist
  7717. --
  7718. if (@queued_check = 1 and @pk_is_identity = 0)
  7719. begin
  7720.     select @cmd = N'
  7721. if not exists (select * from ' + @dest_owner + QUOTENAME(@dest_tabname) + N' '
  7722.     insert into #proctext(procedure_text) values( @cmd )
  7723.     exec @rc = sp_replscriptuniquekeywhereclause @tabid = @src_objid
  7724.                                                         ,@columns = @artcolumns
  7725.                                                         ,@prefix = '@c' 
  7726.                                                         ,@mode = 3
  7727.                                                         ,@paramcount = @param_count
  7728.     if (@@error != 0 or @rc != 0)
  7729.         return 1
  7730.     select @cmd = N')
  7731. begin'
  7732.     insert into #proctext(procedure_text) values( @cmd )
  7733. end
  7734.  
  7735. -- construct update if pk has changed
  7736. select @cmd = N'update ' + @dest_owner + QUOTENAME(@dest_tabname) + N' set'
  7737.  
  7738. -- create SET clause
  7739.  
  7740. select @art_col = 1
  7741. select @spacer = N' '
  7742.  
  7743. DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  7744. select colid from syscolumns where id = @src_objid order by colid asc
  7745.  
  7746. OPEN hCColid
  7747.  
  7748. FETCH hCColid INTO @this_col
  7749. WHILE (@@fetch_status <> -1)
  7750. begin
  7751.     exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
  7752.     if @isset != 0 and EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid and iscomputed<>1)
  7753.     begin
  7754.         if not (@keep_identity = 1 and 
  7755.             columnproperty(@src_objid, col_name( @src_objid, @this_col), 'IsIdentity') = 1)
  7756.         begin
  7757.             select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + 
  7758.                 N' = @c' + convert( nvarchar, @art_col + @param_count/2 ) 
  7759.             select @spacer = N','
  7760.  
  7761.             if len( @cmd ) > 3000
  7762.             begin
  7763.             insert into #proctext(procedure_text) values( @cmd )
  7764.                 select @cmd = N''
  7765.             end
  7766.  
  7767.             --
  7768.             -- Queued processing:if this is the row version column : need to add to where clause
  7769.             --
  7770.             if ((@queued_check = 1) and (col_name( @src_objid, @this_col) = N'msrepl_tran_version'))
  7771.                 select @qwhere_string = N' and msrepl_tran_version = @c' + convert( nvarchar, @art_col )                        
  7772.         end
  7773.         select @art_col = @art_col + 1
  7774.     end
  7775.     FETCH hCColid INTO @this_col
  7776. end
  7777.  
  7778. CLOSE hCColid
  7779. DEALLOCATE hCColid
  7780.  
  7781. insert into #proctext(procedure_text) values( @cmd )
  7782.  
  7783. exec dbo.sp_scriptpkwhereclause @src_objid, @pkcolumns, N'@c', @artcolumns
  7784. if (@queued_check = 1)
  7785. begin
  7786.     insert into #proctext(procedure_text) values( @qwhere_string ) 
  7787.     if (@pk_is_identity = 0)
  7788.     begin
  7789.         select @cmd = N'
  7790. end'
  7791.         insert into #proctext(procedure_text) values( @cmd )
  7792.     end
  7793. end
  7794. else
  7795.     exec dbo.sp_MSscript_missing_row_check
  7796.  
  7797. if @exists_else = 1
  7798.     insert into #proctext(procedure_text) values( N'end' )
  7799.  
  7800. --
  7801. -- End the if exists block for Queued publications
  7802. --
  7803. if (@queued_check = 1) and (@fhasnonpkuniquekeys = 1)
  7804. begin
  7805.     select @cmd = N'
  7806. end'
  7807.     insert into #proctext(procedure_text) values( @cmd )
  7808. end
  7809.  
  7810. -- flush to client
  7811.  
  7812. select procedure_text from #proctext order by c1 asc
  7813. END
  7814. go
  7815. EXEC dbo.sp_MS_marksystemobject sp_scriptxupdproc
  7816. GO
  7817. grant exec on dbo.sp_scriptxupdproc to public
  7818. go
  7819.  
  7820. --------------------------------------------------------------------------------
  7821. --. sp_repltablehasnonpkuniquekey
  7822. --------------------------------------------------------------------------------
  7823.  
  7824. if exists (select * from sysobjects
  7825.     where type = 'P' and name = 'sp_repltablehasnonpkuniquekey')
  7826. drop procedure sp_repltablehasnonpkuniquekey
  7827. go
  7828. raiserror('Creating procedure sp_repltablehasnonpkuniquekey',0,-1)
  7829. go
  7830. create procedure sp_repltablehasnonpkuniquekey 
  7831. (
  7832.     @tabid int              -- id of the table
  7833. )
  7834. as
  7835. begin
  7836.     set nocount on
  7837.     declare @retcode int
  7838.     --
  7839.     -- security check - should be dbo or sysadmin
  7840.     --
  7841.     exec @retcode = dbo.sp_MSreplcheck_publish
  7842.     if @@ERROR != 0 or @retcode != 0
  7843.         return -1
  7844.     --
  7845.     -- process if the object is a table and has index
  7846.     --
  7847.     if (ObjectProperty(@tabid, 'IsTable') = 1) and (ObjectProperty(@tabid, 'TableHasIndex') = 1)
  7848.     begin
  7849.         --
  7850.         -- Set return flag if it is Unique key but not PK
  7851.         --
  7852.         if exists (select indid from sysindexes 
  7853.                 where id = @tabid 
  7854.                     and indid > 0 and indid < 255
  7855.                     and (status & 2) != 0 and (status & 2048) = 0 )
  7856.         begin
  7857.             select @retcode = 1
  7858.         end
  7859.     end
  7860.     --
  7861.     -- all done
  7862.     --
  7863.     return @retcode
  7864. end
  7865. go
  7866. exec sp_MS_marksystemobject sp_repltablehasnonpkuniquekey
  7867. go
  7868.  
  7869. --------------------------------------------------------------------------------
  7870. --. sp_replscriptuniquekeywhereclause
  7871. --------------------------------------------------------------------------------
  7872.  
  7873. if exists (select * from sysobjects
  7874.     where type = 'P' and name = 'sp_replscriptuniquekeywhereclause')
  7875. drop procedure sp_replscriptuniquekeywhereclause
  7876. go
  7877. raiserror('Creating procedure sp_replscriptuniquekeywhereclause', 0,1)
  7878. go
  7879. create procedure sp_replscriptuniquekeywhereclause 
  7880. (
  7881.     @tabid int                                  -- id of the table
  7882.     ,@columns binary(32)                 -- column map for the article
  7883.     ,@prefix nvarchar(10) = '@c'       -- prefix for the scripted column variables
  7884.     ,@suffix nvarchar(10) = null       -- suffix for the scripted column variables
  7885.     ,@mode tinyint                           
  7886.     -- 1 = insert custom proc, 
  7887.     -- 2 = upd custom proc non PK, 
  7888.     -- 3 = upd custom proc PK only 
  7889.     -- 4 = compensating where all keys, 
  7890.     -- 5 = compensating where non PK keys, 
  7891.     -- 6 = refresh cursor all keys,
  7892.     -- 7 = refresh cursor non PK keys
  7893.     -- 8 = compensating where PK only
  7894.     ,@paramcount int = null              -- Total number of parameters - needed for mode = 2 and 3
  7895.  )
  7896. as
  7897. begin
  7898.     set nocount on
  7899.     declare @retcode int
  7900.                 ,@indid int
  7901.                 ,@indstatus int
  7902.                 ,@indkey int
  7903.                 ,@qualname nvarchar(512)
  7904.                 ,@colname sysname
  7905.                 ,@var sysname
  7906.                 ,@artcol int
  7907.                 ,@thiscol int
  7908.                 ,@cmd nvarchar(4000)
  7909.                 ,@findexstarted bit
  7910.                 ,@fisfirstindex bit
  7911.     --
  7912.     -- constants
  7913.     --
  7914.                 ,@modeinscustproc tinyint
  7915.                 ,@modeupdcustprocnonpk tinyint
  7916.                 ,@modeupdcustprocpkonly tinyint
  7917.                 ,@modecompensatingallkeys tinyint
  7918.                 ,@modecompensatingnonpkkeys tinyint
  7919.                 ,@modecompensatingpkonly tinyint
  7920.                 ,@moderefreshcursordeclareallkeys tinyint
  7921.                 ,@moderefreshcursordeclarenonpkkeys tinyint
  7922.  
  7923.     --
  7924.     -- initialize
  7925.     --
  7926.     select @modeinscustproc = 1
  7927.             ,@modeupdcustprocnonpk = 2
  7928.             ,@modeupdcustprocpkonly = 3
  7929.             ,@modecompensatingallkeys = 4
  7930.             ,@modecompensatingnonpkkeys = 5
  7931.             ,@moderefreshcursordeclareallkeys = 6
  7932.             ,@moderefreshcursordeclarenonpkkeys = 7
  7933.             ,@modecompensatingpkonly = 8
  7934.     --
  7935.     -- security check - should be dbo or sysadmin
  7936.     --
  7937.     exec @retcode = dbo.sp_MSreplcheck_publish
  7938.     if @@error != 0 or @retcode != 0
  7939.         return (1)
  7940.     --
  7941.     -- process if the object is a table and has index
  7942.     --
  7943.     if (ObjectProperty(@tabid, 'IsTable') != 1) or (ObjectProperty(@tabid, 'TableHasIndex') != 1)
  7944.         return (1)
  7945.     --
  7946.     -- Get the qualified name of the table
  7947.     --
  7948.     exec @retcode = sp_MSget_qualified_name @tabid, @qualname OUTPUT
  7949.     if @@error != 0 or @retcode != 0 or @qualname is null
  7950.         return (1)
  7951.     --
  7952.     -- @columns cannot be null
  7953.     --
  7954.     if (@columns is null)
  7955.         return (1)
  7956.     --
  7957.     -- Check @mode
  7958.     --
  7959.     if (@mode not in (@modeinscustproc, @modeupdcustprocnonpk, @modeupdcustprocpkonly, 
  7960.                                 @modecompensatingallkeys, @modecompensatingnonpkkeys, 
  7961.                                 @moderefreshcursordeclareallkeys, @moderefreshcursordeclarenonpkkeys,
  7962.                                 @modecompensatingpkonly))
  7963.     begin
  7964.         return (1)
  7965.     end
  7966.     --
  7967.     -- validate @paramcount
  7968.     --
  7969.     if ((@mode in (@modeupdcustprocnonpk,@modeupdcustprocpkonly)) and (@paramcount is null))
  7970.     begin
  7971.         return (1)
  7972.     end
  7973.     --
  7974.     -- enumerate indices
  7975.     -- The scripting will be done as follows :
  7976.     -- A) all keys will include PK and all unique keys
  7977.     --      where (pk1 = @cv and pk2 = @cw ...) or (ui1k1 = @cx and ui1k2 = @cy ...) or (u2k1 = @cz and ...) ...
  7978.     -- B) non PK keys will use only the unique keys that are not part of PK
  7979.     --      where (ui1k1 = @cx and ui1k2 = @cy ...) or (u2k1 = @cz and ...) ...
  7980.     --
  7981.     select @cmd = case when (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly)) 
  7982.                             then N' '' where '
  7983.                             else N' where ' end
  7984.             ,@findexstarted = 0
  7985.             ,@fisfirstindex = 1
  7986.     declare #hcindid cursor local fast_forward for
  7987.         select indid, status from sysindexes 
  7988.                 where id = @tabid and (status & 2) != 0
  7989.                     and indid > 0 and indid < 255
  7990.                     order by indid asc
  7991.     open #hcindid
  7992.     fetch #hcindid into @indid, @indstatus
  7993.     while (@@fetch_status != -1)
  7994.     begin
  7995.         --
  7996.         -- If we are in (@modeupdcustprocnonpk, @modecompensatingnonpkkeys, 
  7997.         -- @moderefreshcursordeclarenonpklkeys) mode then skip processing the PK index.
  7998.         -- If we are in (@modeupdcustprocpkonly, @modecompensatingpkonly) mode 
  7999.         -- skip processing the non PK index
  8000.         --
  8001.         if ((@mode in (@modeupdcustprocnonpk,@modecompensatingnonpkkeys,
  8002.                     @moderefreshcursordeclarenonpkkeys)) and (@indstatus & 2048) != 0) 
  8003.             or ((@mode in (@modeupdcustprocpkonly, @modecompensatingpkonly)) and (@indstatus & 2048) = 0)
  8004.         begin
  8005.             --
  8006.             -- fetch next unique index
  8007.             --
  8008.             fetch #hcindid into @indid, @indstatus
  8009.             continue
  8010.         end
  8011.         --
  8012.         -- Enumerate the keys in this index
  8013.         --
  8014.         select @indkey = 1
  8015.         while (@indkey <= 16)
  8016.         begin
  8017.             --
  8018.             -- get the column name for the key
  8019.             --
  8020.             select @colname = index_col(@qualname, @indid, @indkey)
  8021.             if (@colname is null) 
  8022.                 break
  8023.             --
  8024.             -- check if this column is enabled for replication
  8025.             --
  8026.             select @artcol = 0
  8027.             exec dbo.sp_MSget_col_position @tabid, @columns, @colname, NULL, @artcol output, 0, NULL, @thiscol output
  8028.             if (@artcol > 0)
  8029.             begin
  8030.                 --
  8031.                 -- check if we are scripting the first key for this index
  8032.                 --
  8033.                 if (@findexstarted = 1)
  8034.                 begin
  8035.                     select @cmd = case when (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly)) 
  8036.                                             then @cmd + N' + '' and '
  8037.                                             else @cmd + N' and ' end
  8038.                 end
  8039.                 else
  8040.                 begin
  8041.                     --
  8042.                     -- check if we are scripting the first index. 
  8043.                     --
  8044.                     if (@fisfirstindex = 0)
  8045.                     begin
  8046.                         select @cmd =  @cmd + N' or ' 
  8047.                     end
  8048.                     else
  8049.                     begin
  8050.                         select @fisfirstindex = 0
  8051.                     end
  8052.                     --
  8053.                     -- set @findexstarted while processing the first key
  8054.                     --
  8055.                     select @findexstarted = 1
  8056.                     select @cmd = @cmd + N' ( ' 
  8057.                 end
  8058.                 --
  8059.                 -- script this column
  8060.                 --
  8061.                 if (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly))
  8062.                 begin
  8063.                     --
  8064.                     -- scripting a delete compensating command for synctran proc - we are building a dynamic string
  8065.                     -- case when @c<this_col> is null then '[col<this_col>] is null' else '[col<this_col>] = @c<this_col>' end
  8066.                     --
  8067.                     declare @ccoltype sysname
  8068.  
  8069.                     select @var = @prefix + cast(@thiscol as nvarchar(10))
  8070.                     if (@suffix is not null)
  8071.                         select @var = @var + @suffix
  8072.                     select @cmd = @cmd + N''' + case when ( ' + @var + N' is null) then  '' ' + quotename(@colname) + N' is null '' else '' ' + quotename(@colname)
  8073.                     exec dbo.sp_MSget_colinfo @tabid, @thiscol, @columns, 0, NULL, @ccoltype output
  8074.                     if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar' )
  8075.                         select @cmd = @cmd + N' = '''''' + CAST( master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default as varchar) + '''''''' end ' 
  8076.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
  8077.                         select @cmd = @cmd + N' = N'''''' + master.dbo.fn_MSgensqescstr(' + @var + N') collate database_default + '''''''' end ' 
  8078.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
  8079.                         select @cmd = @cmd + N' = '''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''' end ' 
  8080.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
  8081.                         select @cmd = @cmd + N' = N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @var + N') as nvarchar)) collate database_default + '''''''' end ' 
  8082.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
  8083.                         select @cmd = @cmd + N' = '' + master.dbo.fn_varbintohexstr(' + @var + N') collate database_default end ' 
  8084.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','decimal','numeric'))
  8085.                         select @cmd = @cmd + N' = '' + CAST( ' + @var + N' as nvarchar) end ' 
  8086.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('float','real'))
  8087.                         select @cmd = @cmd + N' = '' + CONVERT(nvarchar(60), ' + @var + N' , 2) end ' 
  8088.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
  8089.                         select @cmd = @cmd + N' = '' + CONVERT(nvarchar(40), ' + @var + N' , 2) end ' 
  8090.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
  8091.                         select @cmd = @cmd + N' = '''''' + CAST( ' + @var + N' as nvarchar(40)) + '''''''' end ' 
  8092.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
  8093.                         select @cmd = @cmd + N' = '''''' + CONVERT(nvarchar(40), ' + @var + N', 112) + N'' '' + CONVERT(nvarchar(40), ' + @var + N', 114) + '''''''' end ' 
  8094.                     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
  8095.                         select @cmd = @cmd + N' = '' + master.dbo.fn_sqlvarbasetostr( ' + @var + N' ) collate database_default  end ' 
  8096.                     else
  8097.                         select @cmd = @cmd + N' = '' + CAST( ' + @var + N' as nvarchar) end ' 
  8098.                 end
  8099.                 else
  8100.                 begin
  8101.                     --
  8102.                     -- scripting for custom procs - static script
  8103.                     -- For publisher scripting - use @thiscol
  8104.                     -- For custom proc scripting - use @artcol
  8105.                     -- For Update custom proc scripting special cases - use variation of @artcol
  8106.                     --
  8107.                     select @var = case when (@mode in (@modeupdcustprocnonpk,@modeupdcustprocpkonly)) 
  8108.                                                     then @prefix + cast((@artcol + @paramcount/2) as nvarchar(10))
  8109.                                                 when (@mode in (@moderefreshcursordeclareallkeys, @moderefreshcursordeclarenonpkkeys))
  8110.                                                     then @prefix + cast(@thiscol as nvarchar(10)) 
  8111.                                                 else @prefix + cast(@artcol as nvarchar(10)) end
  8112.                     if (@suffix is not null)
  8113.                         select @var = @var + @suffix
  8114.                     --
  8115.                     -- Does the column allow NULLs
  8116.                     --
  8117.                     if (columnproperty( @tabid , @colname , 'AllowsNull' ) = 1)
  8118.                     begin
  8119.                         --
  8120.                         -- static scripting should handle NULL valued column
  8121.                         -- ((<@var> is null and <colname> is null) or (<@var> is not null and <colname> = <@var>)) 
  8122.                         --
  8123.                         select @cmd = @cmd + N'((' + @var + N' is null and ' + quotename(@colname) + N' is null) or (' 
  8124.                                                 + @var + N' is not null and ' + quotename(@colname) + N' = ' + @var + N'))' 
  8125.                     end
  8126.                     else
  8127.                     begin
  8128.                         --
  8129.                         -- static scripting does not need to check for NULL values
  8130.                         -- <colname> = <@var>
  8131.                         --
  8132.                         select @cmd = @cmd + quotename(@colname) + N' = ' + @var
  8133.                     end
  8134.                     --
  8135.                     -- special processing for @modeupdcustprocnonpk
  8136.                     --
  8137.                     if (@mode = @modeupdcustprocnonpk)
  8138.                     begin
  8139.                         select @cmd = @cmd + N' and ' + @prefix + cast((@artcol + @paramcount/2) as nvarchar(10))
  8140.                         if (@suffix is not null)
  8141.                             select @cmd = @cmd + @suffix
  8142.                         select @cmd = @cmd + N' != ' + @prefix + cast(@artcol as nvarchar(10))
  8143.                         if (@suffix is not null)
  8144.                             select @cmd = @cmd + @suffix
  8145.                     end
  8146.                 end
  8147.                 --
  8148.                 -- transfer command string to table if too large
  8149.                 --
  8150.                 if (len(@cmd) > 3000)
  8151.                     exec dbo.sp_MSflush_command @cmd output, 1, 0                
  8152.             end            
  8153.             --
  8154.             -- get the next key for the index
  8155.             --
  8156.             select @indkey = @indkey + 1
  8157.         end
  8158.         --
  8159.         -- done with current index
  8160.         --
  8161.         select @findexstarted = 0
  8162.                 ,@cmd = case when (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly)) 
  8163.                                         then @cmd + N' + '' ) '
  8164.                                         else @cmd + N' ) ' end
  8165.         --
  8166.         -- fetch next unique index
  8167.         --
  8168.         fetch #hcindid into @indid, @indstatus
  8169.     end
  8170.     close #hcindid
  8171.     deallocate #hcindid
  8172.     --
  8173.     -- Final flush
  8174.     --
  8175.     if (@mode in (@modecompensatingallkeys, @modecompensatingnonpkkeys, @modecompensatingpkonly))
  8176.         select @cmd = @cmd + N''''
  8177.     if (len(@cmd) > 0)
  8178.         exec dbo.sp_MSflush_command @cmd output, 1, 0                
  8179.     --
  8180.     -- all done
  8181.     --
  8182.     return 0
  8183. end
  8184. go
  8185. exec sp_MS_marksystemobject sp_replscriptuniquekeywhereclause
  8186. go
  8187.  
  8188. -- ------------------------------------------------------------------
  8189. -- Fix final partial empty compensating command problem
  8190. -- ------------------------------------------------------------------
  8191.  
  8192. --------------------------------------------------------------------------------
  8193. --. sp_MSadd_compensating_cmd
  8194. --------------------------------------------------------------------------------
  8195.  
  8196. if exists (select * from sysobjects
  8197.     where type = 'P' and name = 'sp_MSadd_compensating_cmd')
  8198. drop procedure sp_MSadd_compensating_cmd
  8199. go
  8200. raiserror('Creating procedure sp_MSadd_compensating_cmd', 0,1)
  8201. go
  8202. CREATE PROCEDURE sp_MSadd_compensating_cmd(
  8203.     @orig_srv            sysname,
  8204.     @orig_db            sysname,
  8205.     @command            nvarchar(4000),
  8206.     @article_id         int,
  8207.     @publication_id        int,
  8208.     @cmdstate            bit=0,
  8209.     @mode                int=0,
  8210.     @setprefix            bit=1
  8211. )    
  8212. AS
  8213. BEGIN
  8214.     set nocount on
  8215.     declare     
  8216.  
  8217.     --
  8218.     -- variable declarations for all modes
  8219.     --
  8220.                 @retcode            int,
  8221.                 @command_id         int,                -- command sequence
  8222.                 @partial_cmd         int,                -- partial command flag
  8223.                 @curlen                int,                -- current length to read
  8224.                 @start_index        int,                -- index to start reading
  8225.                 @max_fragment        int,                -- max binary fragment
  8226.                 @full_command        nvarchar(4000),        -- qualified command
  8227.                 @readsize            int,                -- read length chars or bytes based on mode
  8228.                 @mode_postpublog     int,
  8229.                 @mode_insdistcmd     int,
  8230.  
  8231.     --
  8232.     -- variable declarations specific to mode = 1
  8233.     --
  8234.  
  8235.                 @partial_cmdbit        bit,                -- partial command flag
  8236.                 @xact_seqno            varbinary(16),
  8237.                 @publisher_id         int,                -- publisher ID
  8238.                 @publisher_db        sysname,             -- publisher Db
  8239.                 @distributor        sysname,            -- distribution server
  8240.                 @distribdb            sysname,            -- distribution db
  8241.                 @charsize            int,                -- char size
  8242.                 @binary_cmd            varbinary(1024),    -- Binary converted command
  8243.                 @distproc            nvarchar(300)        -- RPC string
  8244.  
  8245.     --
  8246.     -- Security Check
  8247.     --
  8248.     exec @retcode = dbo.sp_MSreplcheck_publish
  8249.     if ((@@ERROR != 0) or (@retcode != 0))
  8250.         return(1)
  8251.  
  8252.     --
  8253.     -- Initialize
  8254.     --
  8255.     select         @mode_postpublog = 0,
  8256.                 @mode_insdistcmd = 1
  8257.  
  8258.     if (@mode NOT in (@mode_postpublog,@mode_insdistcmd))
  8259.         return(1)
  8260.     --
  8261.     -- We will not post final partial empty(may contain space) command 
  8262.     -- since logreader skips empty commands and this causes distribution 
  8263.     -- agent to get confused when it selects the commands to read.
  8264.     -- If this partial command happens to be the final partial command which 
  8265.     -- has a single space - then add a comment
  8266.     --
  8267.     if  ((len(@command) = 0) and (@cmdstate = 0))
  8268.         select @command = N'/*c*/'
  8269.     --
  8270.     -- process based on @mode
  8271.     --
  8272.     if (@mode = @mode_insdistcmd)
  8273.     begin
  8274.         select     @publisher_db = db_name(),
  8275.                 @publisher_id = srvid 
  8276.         from master.dbo.sysservers where UPPER(srvname) = UPPER(@@servername) collate database_default
  8277.  
  8278.         --
  8279.         -- Get distribution server information for remote RPC calls
  8280.         --
  8281.         EXECUTE @retcode = dbo.sp_helpdistributor @rpcsrvname = @distributor OUTPUT,
  8282.                                     @distribdb  = @distribdb OUTPUT
  8283.         if ((@@ERROR != 0) or (@retcode != 0))
  8284.             return(1)
  8285.         
  8286.         --
  8287.         -- Get the new xact_seqno
  8288.         --
  8289.         create table #new_xact_seqno ( seqno varbinary(16) NOT NULL )
  8290.         select @distproc = RTRIM(@distributor) + '.' + @distribdb +'.dbo.sp_MSget_new_xact_seqno'
  8291.         insert into #new_xact_seqno
  8292.             EXECUTE @retcode = @distproc
  8293.                 @publisher_id = @publisher_id,
  8294.                 @publisher_db = @publisher_db,
  8295.                 @len = 14
  8296.         if ((@@ERROR != 0) or (@retcode != 0))
  8297.             return(1)
  8298.         select @xact_seqno = seqno from #new_xact_seqno    
  8299.         select @distproc = RTRIM(@distributor) + '.' + @distribdb +'.dbo.sp_MSadd_repl_command'
  8300.     end
  8301.     
  8302.     --
  8303.     -- Do the command insertion in a tran
  8304.     --
  8305.     select @full_command = case when (@setprefix = 1) then 
  8306.                                 QUOTENAME(@orig_srv) + QUOTENAME(@orig_db) + @command
  8307.                                 else @command end
  8308.     begin tran sp_MSadd_compensating_cmd
  8309.     
  8310.     --
  8311.     -- process the command
  8312.     -- for @mode_postpublog : just call sp_replpostcmd and that will do the job
  8313.     -- for @mode_insdistcmd : break the command into 1024 sized commands and add
  8314.     --
  8315.     if (@mode = @mode_postpublog)
  8316.     begin
  8317.         select     @partial_cmd = CASE when (@cmdstate = 1) then 1 else 0 END
  8318.         exec @retcode = dbo.sp_replpostcmd 
  8319.                 @partial_cmd,
  8320.                 @publication_id, 
  8321.                 @article_id, 
  8322.                 12,
  8323.                 @full_command
  8324.         if (@@ERROR != 0 or @retcode != 0)
  8325.             GOTO UNDO
  8326.     end
  8327.     else if (@mode = @mode_insdistcmd)
  8328.     begin
  8329.         select     @command_id = 0,
  8330.                 @start_index = 1,
  8331.                 @max_fragment = 1024,
  8332.                 @charsize = 2,
  8333.                 @curlen = LEN(@full_command),
  8334.                 @readsize = DATALENGTH(@full_command)
  8335.  
  8336.         while (@readsize > 0)
  8337.         begin
  8338.             -- set command id
  8339.             select @command_id = @command_id + 1
  8340.  
  8341.             -- Check if we have to process partial command
  8342.             if (@readsize > @max_fragment)
  8343.             begin
  8344.                 --
  8345.                 -- we have partial command to send
  8346.                 --
  8347.                 select @curlen = @max_fragment / @charsize
  8348.                 select     @partial_cmdbit = 1,
  8349.                         @binary_cmd = CAST(
  8350.                             SUBSTRING(@full_command, @start_index, @curlen)
  8351.                             AS varbinary(1024)),
  8352.                         @readsize = @readsize - @max_fragment
  8353.  
  8354.                 select @start_index = @start_index + @curlen
  8355.                 select @curlen = @readsize / @charsize
  8356.             end
  8357.             else
  8358.             begin
  8359.                 --
  8360.                 -- last fragment to send - end of command
  8361.                 -- check for command state - if state is PARTIAL_CMD (1)
  8362.                 -- then set the partial bit even though this is the last fragment
  8363.                 --
  8364.                 select     @partial_cmdbit = CASE when (@cmdstate = 1) then 1 else 0 END,
  8365.                         @binary_cmd = CAST(
  8366.                             SUBSTRING(@full_command, @start_index, @curlen) 
  8367.                             AS varbinary(1024)),
  8368.                         @readsize = 0
  8369.             end
  8370.                 
  8371.             --
  8372.             -- Add the command to the distributor
  8373.             --
  8374.             EXECUTE @retcode = @distproc
  8375.                 @publisher_id = @publisher_id, 
  8376.                 @publisher_db = @publisher_db, 
  8377.                 @xact_seqno = @xact_seqno,
  8378.                 @type = 12, 
  8379.                 @article_id = @article_id, 
  8380.                 @command_id = @command_id, 
  8381.                 @partial_command = @partial_cmdbit, 
  8382.                 @command = @binary_cmd
  8383.             if (@@ERROR != 0 or @retcode != 0)
  8384.                 GOTO UNDO
  8385.         end -- end of while loop
  8386.     end     -- end of if (@mode = @mode_insdistcmd)
  8387.  
  8388.     --
  8389.     -- Command(s) added successfully - End Tran
  8390.     --
  8391.     commit tran sp_MSadd_compensating_cmd
  8392.     return (0)
  8393.  
  8394. UNDO:
  8395.     --
  8396.     -- Error - Rollback
  8397.     --
  8398.     IF (@@TRANCOUNT > 0)
  8399.     begin
  8400.         ROLLBACK TRAN sp_MSadd_compensating_cmd
  8401.         if (@@TRANCOUNT > 0)
  8402.             COMMIT TRAN   
  8403.     end
  8404.     return (1)    
  8405. END
  8406. go
  8407. EXEC dbo.sp_MS_marksystemobject sp_MSadd_compensating_cmd
  8408. GO
  8409. grant execute on dbo.sp_MSadd_compensating_cmd to public
  8410. go
  8411.  
  8412. --------------------------------------------------------------------------------
  8413. --. sp_MSscript_where_clause
  8414. --------------------------------------------------------------------------------
  8415.  
  8416. if exists (select * from sysobjects
  8417.     where type = 'P' and name = 'sp_MSscript_where_clause')
  8418. drop procedure sp_MSscript_where_clause
  8419. go
  8420. raiserror('Creating procedure sp_MSscript_where_clause', 0,1)
  8421. go
  8422. create procedure sp_MSscript_where_clause (
  8423.     @objid          int,
  8424.     @columns      binary(32), 
  8425.     @clause_type  varchar(15) = 'pk_new', -- 'new pk', 'old pk', 'upd version', 'upd rc', 'trg pk', 'qcft_comp', 'new_pk_q', 'subwins_check'
  8426.     @ts_col       sysname = NULL,
  8427.     @indent       int = 0,
  8428.     @op_type      char(3) = NULL, -- 'ins', 'del', 'upd'
  8429.     @primary_key_bitmap varbinary(4000) = null )
  8430. as
  8431. BEGIN
  8432.     declare    @cmd            nvarchar(4000)
  8433.             ,@colname        sysname
  8434.             ,@ccoltype        sysname
  8435.             ,@spacer        nvarchar(20)
  8436.             ,@indkey        int
  8437.             ,@indid            int
  8438.             ,@key            sysname
  8439.             ,@rc            int
  8440.             ,@this_col        int
  8441.             ,@art_col        int
  8442.             ,@src_cols        int
  8443.             ,@total_col        int
  8444.             ,@col            sysname
  8445.             ,@qualname        nvarchar(512)
  8446.             ,@curparam        nvarchar(20)
  8447.             ,@retcode        int
  8448.             ,@fcreatedcolmap    bit
  8449.     declare @colmap table (relativeorder int identity(1,1), colid int)
  8450.  
  8451.     select @spacer = N' '
  8452.         ,@cmd = N''
  8453.         ,@indkey = 1
  8454.         ,@indid = 0
  8455.         ,@fcreatedcolmap = 0
  8456.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  8457.     select @src_cols = max(colid)
  8458.             ,@total_col = count(colid)
  8459.         from syscolumns where id = @objid
  8460.     exec dbo.sp_MSpad_command @cmd output, @indent
  8461.     if (@clause_type = 'qcft_comp')
  8462.         select @cmd = @cmd + N' '' where '
  8463.     else
  8464.         select @cmd = @cmd + N'where'
  8465.     exec dbo.sp_MSflush_command @cmd output, 1, @indent
  8466.  
  8467.     if @clause_type in ('new pk','old pk','upd version','trg pk','version pk','qcft_comp','new_pk_q','subwins_check')
  8468.     begin
  8469.         if @primary_key_bitmap is null
  8470.         begin
  8471.             exec @indid = dbo.sp_MStable_has_unique_index @objid
  8472.             if @indid is null
  8473.             begin
  8474.                 raiserror('Debug: Cannot find unique index', 16, -1)
  8475.                 return (1)
  8476.             end
  8477.         end
  8478.  
  8479.         --
  8480.         -- check if column Id match relative column order
  8481.         -- for specific trigger operations
  8482.         --
  8483.         if ((@total_col < @src_cols) and (@clause_type = 'trg pk') and 
  8484.             (@columns is null) and (@primary_key_bitmap is not null))
  8485.         begin
  8486.             --
  8487.             -- this table may have altered columns, so when we need to 
  8488.             -- set a mapping for using the bitmaps properly as the bitmap
  8489.             -- always refers relative column order
  8490.             --
  8491.             insert into @colmap (colid)
  8492.                 select colid from syscolumns where id = @objid order by colid
  8493.             if (@@error != 0)
  8494.             begin
  8495.                 raiserror('Could not create column mapping', 16, -1)
  8496.                 return (1)
  8497.             end
  8498.             select @fcreatedcolmap = 1
  8499.         end
  8500.         
  8501.         while (1=1)
  8502.         begin
  8503.             --
  8504.             -- get the column position
  8505.             --
  8506.                 if @primary_key_bitmap is null 
  8507.                 begin
  8508.                          select @key = index_col(@qualname, @indid, @indkey)
  8509.                          if @key is null
  8510.                              break
  8511.                          --exec dbo.sp_MSget_col_position @objid, @columns, @key, @col output, @this_col output
  8512.                          exec dbo.sp_MSget_col_position @objid, @columns, @key, @col output, NULL, 0, NULL, @this_col output
  8513.                 end
  8514.                 else
  8515.                 begin
  8516.                     exec dbo.sp_MSget_map_position @primary_key_bitmap, @indkey, @col output, @this_col output
  8517.                     if @this_col is null
  8518.                         break
  8519.  
  8520.                 --
  8521.                 -- set the actual column id for this relative order in the PK bitmap if necessary
  8522.                 --
  8523.                 if (@fcreatedcolmap = 1)
  8524.                 begin
  8525.                     select @this_col = colid
  8526.                         ,@col = 'c' + convert(sysname, colid) 
  8527.                     from @colmap 
  8528.                     where relativeorder = @this_col 
  8529.                 end
  8530.                 end
  8531.  
  8532.             --
  8533.             -- Get column name
  8534.             --
  8535.             exec @retcode = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @key output, @ccoltype output
  8536.             if (@retcode = 1)
  8537.             begin
  8538.                 --
  8539.                 -- this column not used for replication
  8540.                 -- continue
  8541.                 --
  8542.                 select @indkey = @indkey + 1
  8543.                 continue
  8544.             end
  8545.         
  8546.             if @clause_type = 'new pk'
  8547.             begin
  8548.                 if ColumnProperty(@objid, @key, 'IsIdentity') = 1
  8549.                     select @cmd = @cmd + @spacer + quotename(@key) + N' = @@identity'
  8550.                 else
  8551.                     select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col
  8552.  
  8553.                 select @spacer = ' and '
  8554.             end
  8555.             else if @clause_type in ('upd version', 'subwins_check')
  8556.             begin
  8557.                 select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col + N'_old'
  8558.                 select @spacer = ' and '
  8559.             end
  8560.             else if @clause_type = 'version pk'
  8561.             begin
  8562.                 select @cmd = @cmd + @spacer + @qualname + '.' + quotename(@key) + N' = inserted.' + quotename(@key)
  8563.                 select @spacer = ' and
  8564.     '
  8565.             end
  8566.             else if @clause_type in ('trg pk', 'old pk')
  8567.             begin                
  8568.                 if @op_type = 'ins'
  8569.                     select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col + N'_old'
  8570.                 else
  8571.                     -- The vars correspoding to pk were set in sp_MSscript
  8572.                     -- _pkvar_assignment.
  8573.                     select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col 
  8574.                 select @spacer = ' and
  8575.     '
  8576.             end
  8577.             else if (@clause_type = 'qcft_comp')
  8578.             begin
  8579.                 --
  8580.                 -- Conflict compensation generation
  8581.                 -- This is a special case - we generate
  8582.                 -- and exec string for the WHERE clause
  8583.                 --
  8584.                 if (@op_type = 'ins')
  8585.                     select @curparam = N'@' + @col
  8586.                 else if (@op_type = 'del')
  8587.                     select @curparam = N'@' + @col + N'_old'
  8588.                 else
  8589.                     select @curparam = N'ISNULL(@' + @col + N', @' + @col + N'_old)'
  8590.                 
  8591.                 select @cmd = @cmd + @spacer + quotename(@key)
  8592.                 
  8593.                 if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar')
  8594.                     select @cmd = @cmd + N' = '' + '''''''' + master.dbo.fn_MSgensqescstr(' + @curparam + N') collate database_default + '''''''' '
  8595.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
  8596.                     select @cmd = @cmd + N' = '' + ''N'''''' + master.dbo.fn_MSgensqescstr(' + @curparam + N') collate database_default + '''''''' '
  8597.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
  8598.                     select @cmd = @cmd + N' = '' + '''''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @curparam + N') as nvarchar)) collate database_default + '''''''' '
  8599.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
  8600.                     select @cmd = @cmd + N' = '' + ''N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @curparam + N') as nvarchar)) collate database_default + '''''''' '
  8601.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
  8602.                     select @cmd = @cmd + N' = '' + master.dbo.fn_varbintohexstr(' + @curparam + N') collate database_default ' 
  8603.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','decimal','numeric'))
  8604.                     select @cmd = @cmd + N' = '' + CAST(' + @curparam + N' as nvarchar) '
  8605.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('float','real'))
  8606.                     select @cmd = @cmd + N' = '' + CONVERT(nvarchar(60),' + @curparam + N', 2) '
  8607.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
  8608.                     select @cmd = @cmd + N' = '' + CONVERT(nvarchar(40),' + @curparam + N', 2) '
  8609.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
  8610.                     select @cmd = @cmd + N' = '' + '''''''' + CAST(' + @curparam + N' as nvarchar(40)) + '''''''' '
  8611.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
  8612.                     select @cmd = @cmd + N' = '' + '''''''' + CONVERT(nvarchar(40), ' + @curparam + N', 112) + N'' '' + CONVERT(nvarchar(40), ' + @curparam + N', 114) + '''''''' '    
  8613.                 else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
  8614.                     select @cmd = @cmd + N' = '' + master.dbo.fn_sqlvarbasetostr(' + @curparam + N' ) collate database_default '
  8615.                 else
  8616.                     select @cmd = @cmd + N' = '' + CAST(' + @curparam + N' as nvarchar) '
  8617.                 
  8618.                 select @spacer = ' + '' and  '
  8619.             end
  8620.             else if @clause_type = 'new_pk_q'
  8621.             begin
  8622.                 --
  8623.                 -- new value of primary key, ignore identity
  8624.                 -- used for scripting in synctran procs
  8625.                 --
  8626.                 select @cmd = @cmd + @spacer + quotename(@key) + N' = @' + @col
  8627.                 select @spacer = ' and '
  8628.             end
  8629.             select @indkey = @indkey + 1
  8630.  
  8631.             -- flush command if necessary
  8632.             exec dbo.sp_MSflush_command @cmd output, 1, @indent
  8633.         end -- end of while loop
  8634.         
  8635.         -- add version col as necessary
  8636.         if ((@clause_type in ('upd version','subwins_check')) and (@ts_col is not null))
  8637.         begin
  8638.             --
  8639.             -- @ts_col is version col actually.
  8640.             -- check for special cases for queued processing
  8641.             --
  8642.             exec dbo.sp_MSget_col_position @objid, @columns, @ts_col, @col output
  8643.             if (@clause_type = 'subwins_check')
  8644.                 select @cmd = @cmd + @spacer + @ts_col + N' = @' + @col
  8645.             else
  8646.                 select @cmd = @cmd + @spacer + @ts_col + N' = @' + @col + N'_old'
  8647.  
  8648.             --
  8649.             -- save off command fragment
  8650.             --
  8651.             exec dbo.sp_MSflush_command @cmd output, 1, @indent
  8652.         end
  8653.     end -- end of if clause_type
  8654.     -- 'upd rc' is used for column value conflict detection. It is no longer used.
  8655.     else if @clause_type = 'upd rc'
  8656.     begin
  8657.         select @this_col = 1, @art_col = 1
  8658.         while @this_col <= @src_cols
  8659.         begin
  8660.             exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @colname output, @ccoltype output
  8661.             if @rc = 0
  8662.             begin
  8663.                 select @cmd = @cmd +  @spacer + '(' + @colname + N' = @c' + convert(varchar(4), @this_col) + N'_old or (' 
  8664.                 select @cmd = @cmd + @colname + ' is null and @c' + convert(varchar(4), @this_col) + N'_old is null)) '
  8665.                 select @spacer = N' and 
  8666.     '
  8667.                 exec dbo.sp_MSflush_command @cmd output, 0, @indent
  8668.             end
  8669.             exec dbo.sp_MSflush_command @cmd output, 1, @indent
  8670.             select @this_col = @this_col + 1
  8671.         end
  8672.  
  8673.         -- save off cmd fragment
  8674.         exec dbo.sp_MSflush_command @cmd output, 1, @indent
  8675.     end
  8676.     
  8677. END
  8678. go
  8679. EXEC dbo.sp_MS_marksystemobject sp_MSscript_where_clause
  8680. GO
  8681.  
  8682. --------------------------------------------------------------------------------
  8683. --. sp_MSmaketrancftproc
  8684. --------------------------------------------------------------------------------
  8685.  
  8686. if exists (select * from sysobjects
  8687.     where type = 'P' and name = 'sp_MSmaketrancftproc')
  8688. drop procedure sp_MSmaketrancftproc
  8689. go
  8690. raiserror('Creating procedure sp_MSmaketrancftproc', 0,1)
  8691. go
  8692. create procedure sp_MSmaketrancftproc (
  8693.     @article sysname, 
  8694.     @publication sysname,
  8695.     @is_debug bit=0)
  8696. as
  8697. BEGIN
  8698. declare @source_table nvarchar(540)
  8699.         ,@owner sysname
  8700.         ,@procname sysname
  8701.         ,@source_objid int
  8702.         ,@artid int
  8703.         ,@pubid int
  8704.         ,@conflict_tableid int
  8705.         ,@conflict_table    sysname
  8706.         ,@conflict_proc_id int
  8707.         ,@indid int
  8708.         ,@indkey int
  8709.         ,@ind_col_name sysname
  8710.         ,@qualname   nvarchar(540)
  8711.         ,@destqualname   nvarchar(540)
  8712.         ,@destowner sysname
  8713.         ,@dbname sysname
  8714.         ,@retcode smallint
  8715.         ,@retain_varname int
  8716.  
  8717. declare @colid        int
  8718.         ,@colname    sysname
  8719.         ,@coltype    sysname
  8720.         ,@ccoltype    sysname
  8721.         ,@rowcnt    int
  8722.  
  8723. declare @argtabempty    bit
  8724.         ,@seltabempty    bit
  8725.         ,@sel2tabempty    bit
  8726.         ,@valtabempty     bit
  8727.         ,@paramtabempty    bit
  8728.         ,@where_clausetabempty bit
  8729.         ,@decltabempty bit
  8730.         ,@assigntabempty bit
  8731.         ,@compinsertabempty bit
  8732.  
  8733. declare @argterm    nvarchar(4000)
  8734.         ,@selterm    nvarchar(4000)
  8735.         ,@sel2term    nvarchar(4000)
  8736.         ,@updterm    nvarchar(4000)
  8737.         ,@valterm     nvarchar(4000)
  8738.         ,@paramterm    nvarchar(4000)
  8739.         ,@where_term nvarchar(4000)
  8740.         ,@declterm    nvarchar(4000)
  8741.         ,@assignterm nvarchar(4000)
  8742.         ,@compinsterm nvarchar(4000)
  8743.  
  8744. declare @cmd        nvarchar(4000)
  8745.  
  8746. set nocount on
  8747.  
  8748. --
  8749. -- prepare the proc name and get the other parameters
  8750. --
  8751. select @artid = a.artid, @pubid = a.pubid, @source_table = object_name(a.objid), 
  8752.         @source_objid = a.objid, @destowner = a.dest_owner 
  8753. from sysarticles a, syspublications p
  8754.         where a.name = @article and
  8755.               p.name = @publication and
  8756.               a.pubid = p.pubid
  8757.  
  8758. -- Get the object owner name
  8759. select @owner = u.name 
  8760. from sysusers u, sysobjects o 
  8761. where o.id = @source_objid and o.uid = u.uid
  8762.  
  8763. --
  8764. -- Prepare the proc name 
  8765. -- The source table should be owner qualified
  8766. --
  8767. select @source_table = QUOTENAME(@owner) + N'.' + QUOTENAME(@source_table)
  8768. exec @retcode = sp_MSgettranconflictname @publication=@publication, 
  8769.                     @source_object= @source_table, 
  8770.                     @str_prefix='sp_MScft_', 
  8771.                     @conflict_table=@procname OUTPUT
  8772.  
  8773. --
  8774. -- The conflict table should exist before we do any conflict procs
  8775. --
  8776. select @conflict_tableid = conflict_tableid, 
  8777.         @conflict_table = OBJECT_NAME(conflict_tableid) 
  8778. from sysarticleupdates
  8779. where artid = @artid and pubid = @pubid
  8780. if ( @conflict_tableid is NULL)
  8781.     return (1)
  8782. --
  8783. -- To check if specified object exists in current database
  8784. --
  8785. select @qualname = case when (@owner is null or @owner = ' ') then QUOTENAME(@conflict_table)
  8786.                     else QUOTENAME(@owner) + N'.' + QUOTENAME(@conflict_table) end
  8787. if (object_id(@qualname) is NULL)
  8788.     return (1)
  8789.  
  8790. --
  8791. -- The source table should have an unique index
  8792. --
  8793. exec @indid = dbo.sp_MStable_has_unique_index @source_objid
  8794. if (@indid = 0)
  8795.     return (1)
  8796.  
  8797. --
  8798. -- Get all the columns participating in the index of the source table
  8799. --
  8800. create table #indcoltab ( colname sysname collate database_default )
  8801. select @indkey = 1;
  8802. while (@indkey <= 16)
  8803. begin
  8804.     select @ind_col_name = index_col(@source_table, @indid, @indkey)
  8805.     if (@ind_col_name is not NULL) 
  8806.         insert into #indcoltab(colname) values(@ind_col_name)
  8807.     else
  8808.         select @indkey = 16
  8809.  
  8810.     select @indkey = @indkey + 1
  8811. end
  8812.  
  8813. --
  8814. -- prepare destination table name (required for decentralized conflict processing)
  8815. --
  8816. select @destqualname = case when (@destowner is null or @destowner = ' ') 
  8817.                     then QUOTENAME(@conflict_table)
  8818.                     else QUOTENAME(@destowner) + N'.' + QUOTENAME(@conflict_table) end
  8819.  
  8820. -- build the lists
  8821. select @argtabempty = 1
  8822.     ,@valtabempty = 1
  8823.     ,@paramtabempty = 1
  8824.     ,@seltabempty = 1
  8825.     ,@sel2tabempty = 1
  8826.     ,@decltabempty = 1
  8827.     ,@assigntabempty = 1
  8828.     ,@where_clausetabempty = 1
  8829.     ,@compinsertabempty = 1
  8830.  
  8831. create table #argtab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  8832. create table #valtab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  8833. create table #paramtab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  8834. create table #seltab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  8835. create table #sel2tab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  8836. create table #decltab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  8837. create table #assigntab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  8838. create table #where_clausetab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  8839. create table #compinstab ( c1 int identity NOT NULL, procedure_text nvarchar(4000) collate database_default null)
  8840.  
  8841. -- some predefined declares and assignments
  8842. select @cmd = N'
  8843.     declare @reinit_code int, @subwins_code int, @pubwins_code int, @qcfttabrowid uniqueidentifier
  8844.             ,@retcode smallint, @compcmd nvarchar(4000), @centralized_conflicts bit'
  8845. insert into #decltab(procedure_text) values(@cmd)
  8846. select @decltabempty = 0
  8847.     
  8848. select @cmd = N'
  8849.     select @reinit_code = 3
  8850.             ,@subwins_code = 2
  8851.             ,@pubwins_code = 1
  8852.             ,@qcfttabrowid = NEWID()'
  8853. insert into #assigntab(procedure_text) values(@cmd)
  8854. select @cmd = N'
  8855.     select @centralized_conflicts = centralized_conflicts
  8856.     from dbo.syspublications where pubid = ' + cast(@pubid as nvarchar)
  8857. insert into #assigntab(procedure_text) values(@cmd)
  8858. select @assigntabempty = 0
  8859.     
  8860. declare #argcursor cursor local FAST_FORWARD FOR 
  8861.         select colid
  8862.         from syscolumns
  8863.         where iscomputed = 0 and id=@conflict_tableid 
  8864.         order by colid
  8865. FOR READ ONLY
  8866.  
  8867. select @retain_varname = 0
  8868. open #argcursor
  8869. fetch #argcursor into @colid
  8870. while (@@FETCH_STATUS = 0)
  8871. begin
  8872.     --
  8873.     -- Get the column name and column type
  8874.     --
  8875.     exec dbo.sp_MSget_type @conflict_tableid, @colid, @colname output, @coltype OUTPUT
  8876.     if (@@ERROR<>0 or @retcode<>0)
  8877.         return (1)
  8878.  
  8879.     --
  8880.     -- skip this specific column or if type is not returned
  8881.     --
  8882.     if ((@coltype IS NULL) or (LOWER(@colname) = 'qcfttabrowid'))
  8883.     begin
  8884.         -- do the next fetch and continue
  8885.         fetch #argcursor into @colid
  8886.         continue    
  8887.     end
  8888.         
  8889.     exec dbo.sp_MSget_colinfo @conflict_tableid, @colid, NULL, 0, NULL, @ccoltype output
  8890.     if (@@ERROR<>0 or @retcode<>0)
  8891.         return (1)
  8892.  
  8893.     --
  8894.     -- parameterize the vars that are the column values of the source
  8895.     -- table. For the columns that are specific to the conflict table
  8896.     -- retain specific names for the vars
  8897.     --
  8898.     if (LOWER(@colname collate SQL_Latin1_General_CP1_CS_AS) = 'origin_datasource')
  8899.         select @retain_varname = @colid
  8900.  
  8901.     if (@retain_varname = 0)
  8902.         select @argterm = N'@param' + cast(@colid as nvarchar) 
  8903.     else
  8904.         select @argterm = N'@' + @colname
  8905.         
  8906.     select @valterm = quotename(@colname)
  8907.     select @paramterm = @argterm
  8908.     select @updterm = @valterm + N' = ' + @argterm
  8909.  
  8910.     if (@retain_varname = 0)
  8911.     begin
  8912.         select @selterm = @paramterm + N' = ' + @valterm
  8913.         select @sel2term = @paramterm + N' = case when ' + @paramterm + 
  8914.                     N' is NULL then ' + @valterm + N' else ' + @paramterm + N' end'
  8915.     end
  8916.     else
  8917.     begin
  8918.         select @selterm = NULL
  8919.         select @sel2term = NULL
  8920.     end
  8921.      
  8922.     select @argterm = @argterm + N' ' + @coltype
  8923.  
  8924.     -- Check if this is part of primary key    / unique index
  8925.     if (@colname in ( select colname from #indcoltab ) )
  8926.     begin
  8927.         -- this key assignment becomes part of where clause
  8928.         select @where_term = @updterm
  8929.         select @updterm = NULL
  8930.         select @selterm = NULL
  8931.         select @sel2term = NULL
  8932.     end
  8933.     else
  8934.         select @where_term = NULL
  8935.  
  8936.     -- special columns - process them as local var
  8937.     if (LOWER(@colname collate SQL_Latin1_General_CP1_CS_AS) = 'insertdate' )
  8938.     begin
  8939.         select @declterm = N'
  8940.     declare ' + @argterm
  8941.         select @assignterm = N'
  8942.     select ' + @paramterm + N' = GETDATE()'
  8943.         select @argterm = NULL
  8944.     end
  8945.     else if (LOWER(@colname collate SQL_Latin1_General_CP1_CS_AS) = 'pubid' )
  8946.     begin
  8947.         select @declterm = N'
  8948.     declare ' + @argterm
  8949.         select @assignterm = N'
  8950.     select ' + @paramterm + N' = ' + cast(@pubid as nvarchar)
  8951.         select @argterm = NULL
  8952.     end
  8953.     else
  8954.     begin
  8955.         select @declterm = NULL
  8956.         select @assignterm = NULL
  8957.     end
  8958.  
  8959.     -- build the term for compensating insert
  8960.     if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar')
  8961.         select @compinsterm = N' '''''' + master.dbo.fn_MSgensqescstr(' + @valterm + N') collate database_default + '''''''' '
  8962.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
  8963.         select @compinsterm = N' N'''''' + master.dbo.fn_MSgensqescstr(' + @valterm + N') collate database_default + '''''''' '
  8964.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
  8965.         select @compinsterm = N' '''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @valterm + N') as nvarchar(4000))) collate database_default + '''''''' '
  8966.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
  8967.         select @compinsterm = N' N'''''' + master.dbo.fn_MSgensqescstr(CAST(RTRIM(' + @valterm + N') as nvarchar(4000))) collate database_default + '''''''' '
  8968.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
  8969.         select @compinsterm = N' '' + master.dbo.fn_varbintohexstr(' + @valterm + N') collate database_default ' 
  8970.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','decimal','numeric'))
  8971.         select @compinsterm = N' '' + CAST(' + @valterm + N' as nvarchar) '
  8972.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('float','real'))
  8973.         select @compinsterm = N' '' + CONVERT(nvarchar(60),' + @valterm + N', 2) '
  8974.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
  8975.         select @compinsterm = N' '' + CONVERT(nvarchar(40),' + @valterm + N', 2) '
  8976.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
  8977.         select @compinsterm = N' '''''' + CAST(' + @valterm + N' as nvarchar(40)) + '''''''' '
  8978.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
  8979.         select @compinsterm = N' '''''' + CONVERT(nvarchar(40), ' + @valterm + N', 112) + N'' ''  + CONVERT(nvarchar(40), ' + @valterm + N', 114) + '''''''' '
  8980.     else if (lower(@ccoltype collate SQL_Latin1_General_CP1_CS_AS) = 'sql_variant')
  8981.         select @compinsterm = N' '' + master.dbo.fn_sqlvarbasetostr(' + @valterm + N' ) collate database_default '
  8982.     else
  8983.         select @compinsterm = N' '' + CAST(' + @valterm + N' as nvarchar) '
  8984.     
  8985.     -- Now append to the various lists
  8986.     if (@argterm is NOT NULL)
  8987.     begin        
  8988.         if (@argtabempty = 1)
  8989.         begin
  8990.             select @argtabempty = 0
  8991.             select @cmd = N'
  8992.     ' + @argterm
  8993.         end
  8994.         else
  8995.             select @cmd = N',
  8996.     ' + @argterm
  8997.         insert into #argtab(procedure_text) values(@cmd)
  8998.     end
  8999.     if (@valterm is NOT NULL)
  9000.     begin
  9001.         if (@valtabempty = 1)
  9002.         begin
  9003.             select @valtabempty = 0
  9004.             select @cmd = @valterm
  9005.         end
  9006.         else
  9007.             select @cmd = N', ' + @valterm
  9008.         insert into #valtab(procedure_text) values(@cmd)
  9009.     end
  9010.     if (@paramterm is NOT NULL)
  9011.     begin
  9012.         if (@paramtabempty = 1)
  9013.         begin
  9014.             select @paramtabempty = 0
  9015.             select @cmd = @paramterm
  9016.         end
  9017.         else
  9018.             select @cmd = N', ' + @paramterm
  9019.         insert into #paramtab(procedure_text) values(@cmd)
  9020.     end
  9021.     if (@selterm is NOT NULL)
  9022.     begin
  9023.         if (@seltabempty = 1)
  9024.         begin
  9025.             select @seltabempty = 0
  9026.             select @cmd = N'
  9027.         ' + @selterm
  9028.         end
  9029.         else
  9030.             select @cmd = N'
  9031.         ,' + @selterm        
  9032.         insert into #seltab(procedure_text) values(@cmd)
  9033.     end
  9034.     if (@sel2term is NOT NULL)
  9035.     begin
  9036.         if (@sel2tabempty = 1)
  9037.         begin
  9038.             select @sel2tabempty = 0
  9039.             select @cmd = N'
  9040.         ' + @sel2term
  9041.         end
  9042.         else
  9043.             select @cmd = N'
  9044.         ,' + @sel2term        
  9045.         insert into #sel2tab(procedure_text) values(@cmd)
  9046.     end    
  9047.     if (@where_term is NOT NULL)
  9048.     begin
  9049.         if (@where_clausetabempty = 1)
  9050.         begin
  9051.             select @where_clausetabempty = 0
  9052.             select @cmd = @where_term
  9053.         end
  9054.         else
  9055.             select @cmd = N' AND 
  9056.             ' + @where_term
  9057.         insert into #where_clausetab(procedure_text) values(@cmd)
  9058.     end
  9059.     if (@declterm is NOT NULL)
  9060.     begin
  9061.         select @cmd = @declterm + N'
  9062.     '
  9063.         insert into #decltab(procedure_text) values(@cmd)
  9064.     end        
  9065.  
  9066.     if (@assignterm is NOT NULL)
  9067.     begin
  9068.         select @cmd = @assignterm + N'
  9069.     '
  9070.         insert into #assigntab(procedure_text) values(@cmd)
  9071.     end        
  9072.  
  9073.     if (@compinsterm is NOT NULL)
  9074.     begin
  9075.         if (@compinsertabempty = 1)
  9076.         begin
  9077.             select @compinsertabempty = 0
  9078.             select @cmd = N' + ISNULL(''' + @compinsterm + N', ''null'')'
  9079.         end
  9080.         else
  9081.             select @cmd = N' + ISNULL('',' + @compinsterm + N', ''null'')'
  9082.         insert into #compinstab(procedure_text) values(@cmd)
  9083.     end
  9084.     
  9085.     -- do the next fetch
  9086.     fetch #argcursor into @colid
  9087.  
  9088. end
  9089. close #argcursor
  9090. deallocate #argcursor
  9091. drop table #indcoltab
  9092.  
  9093. --
  9094. -- generation phase
  9095. --
  9096. BEGIN TRAN sp_MSmaketrancftproc
  9097.  
  9098. -- create temp table to select the command text out of
  9099. if exists (select * from sysobjects where name = 'tempcmd' and uid = user_id('dbo'))
  9100.         drop table dbo.tempcmd
  9101. create table dbo.tempcmd ( c1 int identity NOT NULL, cmdtext nvarchar(4000) NULL)
  9102.  
  9103. -- create header
  9104. insert into  dbo.tempcmd(cmdtext) 
  9105. values(N'create procedure '+QUOTENAME(@owner)+ N'.'+ QUOTENAME(@procname) + N'( 
  9106. ')
  9107.  
  9108. -- insert the arglist
  9109. insert into dbo.tempcmd(cmdtext) select procedure_text from #argtab order by c1 
  9110. insert into dbo.tempcmd(cmdtext) values(N' ,@subcriber sysname = NULL, @subdb sysname = NULL )
  9111. as
  9112. begin
  9113. ')
  9114.  
  9115. -- insert the declare list
  9116. insert into dbo.tempcmd(cmdtext) select procedure_text from #decltab order by c1 
  9117. insert into dbo.tempcmd(cmdtext) values(N'
  9118. ')
  9119.  
  9120. -- insert the assignment list (for declared vars)
  9121. insert into dbo.tempcmd(cmdtext) select procedure_text from #assigntab order by c1
  9122.  
  9123. -- do the select for the case where we need to retain values of publisher
  9124. insert into dbo.tempcmd(cmdtext) values(N'
  9125.     if (@reason_code = @subwins_code)
  9126.     begin
  9127.         select ')
  9128. insert into dbo.tempcmd(cmdtext) select procedure_text from #seltab order by c1
  9129. insert into dbo.tempcmd(cmdtext) values(N'
  9130.         from ' + @source_table + N' where ')
  9131. insert into dbo.tempcmd(cmdtext) select procedure_text from #where_clausetab order by c1
  9132. insert into dbo.tempcmd(cmdtext) values(N'
  9133.     end')
  9134.  
  9135. insert into dbo.tempcmd(cmdtext) values(N'
  9136.     else
  9137.     begin
  9138.         select ')
  9139.     
  9140. insert into dbo.tempcmd(cmdtext) select procedure_text from #sel2tab order by c1
  9141. insert into dbo.tempcmd(cmdtext) values(N'
  9142.         from ' + @source_table + N' where ')
  9143. insert into dbo.tempcmd(cmdtext) select procedure_text from #where_clausetab order by c1
  9144. insert into dbo.tempcmd(cmdtext) values(N'
  9145.     end
  9146. ')
  9147.  
  9148. --
  9149. -- insert the conflict row in the publisher cft table
  9150. --
  9151. insert into dbo.tempcmd(cmdtext) values(N'
  9152.     insert into ' + @qualname + N'(')
  9153. insert into dbo.tempcmd(cmdtext) select procedure_text from #valtab order by c1
  9154. insert into dbo.tempcmd(cmdtext) values(N',[qcfttabrowid]) 
  9155.     values (')
  9156. insert into dbo.tempcmd(cmdtext) select procedure_text from #paramtab order by c1
  9157. insert into dbo.tempcmd(cmdtext) values(N',@qcfttabrowid)
  9158. ')
  9159.  
  9160. --
  9161. -- generate compensating command decentralized logging
  9162. -- depending on the number of columns, we will split the compensating
  9163. -- command into several compensating commands
  9164. --
  9165. select @rowcnt = 0, @compinsertabempty = 1
  9166. select @cmd = N'
  9167.     if (@centralized_conflicts = 0)
  9168.     begin
  9169.         select @compcmd = N''insert into ' + master.dbo.fn_MSgensqescstr(@destqualname) collate database_default + N' ( '
  9170. insert into dbo.tempcmd(cmdtext) values(@cmd)
  9171.  
  9172. declare #htempcur cursor local for
  9173.     select master.dbo.fn_MSgensqescstr(procedure_text) from #valtab order by c1
  9174. for read only
  9175.  
  9176. open #htempcur
  9177. fetch #htempcur into @compinsterm
  9178. while (@@fetch_status = 0)
  9179. begin
  9180.     insert into dbo.tempcmd(cmdtext) select @compinsterm
  9181.     select @rowcnt = @rowcnt + 1
  9182.  
  9183.     --
  9184.     -- if we have processed 10 terms then split the command
  9185.     --
  9186.     if (@rowcnt > 9)
  9187.     begin
  9188.         select @cmd = N'''
  9189.         from ' + @qualname + N' where qcfttabrowid = @qcfttabrowid and tranid = @tranid' 
  9190.         insert into dbo.tempcmd(cmdtext) values(@cmd)        
  9191.     
  9192.         select @cmd = N'
  9193.         exec @retcode = dbo.sp_MSadd_compensating_cmd @subcriber, @subdb, @compcmd, ' 
  9194.             + CAST(@artid as nvarchar(10)) + N', ' + CAST(@pubid as nvarchar(10)) + N',1,0,'
  9195.             + CAST(@compinsertabempty as nvarchar(4)) + N'
  9196.         if (@@error != 0 or @retcode != 0)
  9197.             return 1 
  9198.         
  9199.         select @compcmd = N''' 
  9200.         insert into dbo.tempcmd(cmdtext) values(@cmd)
  9201.         select @rowcnt = 0, @compinsertabempty = 0
  9202.     end
  9203.     fetch #htempcur into @compinsterm
  9204. end
  9205.  
  9206. close #htempcur
  9207. deallocate #htempcur
  9208.  
  9209. insert into dbo.tempcmd(cmdtext) values(N', [qcfttabrowid] ) values ('' ')
  9210. select @rowcnt = @rowcnt + 1
  9211.  
  9212. declare #htempcur cursor local for
  9213.     select procedure_text from #compinstab order by c1
  9214. for read only
  9215.  
  9216. open #htempcur
  9217. fetch #htempcur into @compinsterm
  9218. while (@@fetch_status = 0)
  9219. begin
  9220.     insert into dbo.tempcmd(cmdtext) select @compinsterm
  9221.     select @rowcnt = @rowcnt + 1
  9222.  
  9223.     --
  9224.     -- if we have processed 10 terms then split the command
  9225.     --
  9226.     if (@rowcnt > 9)
  9227.     begin
  9228.         select @cmd = N'
  9229.         from ' + @qualname + N' where qcfttabrowid = @qcfttabrowid and tranid = @tranid' 
  9230.         insert into dbo.tempcmd(cmdtext) values(@cmd)        
  9231.     
  9232.         select @cmd = N'
  9233.         exec @retcode = dbo.sp_MSadd_compensating_cmd @subcriber, @subdb, @compcmd, ' 
  9234.             + CAST(@artid as nvarchar(10)) + N', ' + CAST(@pubid as nvarchar(10)) + N',1,0,'
  9235.             + CAST(@compinsertabempty as nvarchar(4)) + N'
  9236.         if (@@error != 0 or @retcode != 0)
  9237.             return 1 
  9238.         
  9239.         select @compcmd = N'' ''' 
  9240.         insert into dbo.tempcmd(cmdtext) values(@cmd)
  9241.         select @rowcnt = 0, @compinsertabempty = 0
  9242.     end
  9243.     fetch #htempcur into @compinsterm
  9244. end
  9245.  
  9246. close #htempcur
  9247. deallocate #htempcur
  9248.  
  9249. --
  9250. -- script the remaining compensating command
  9251. --
  9252. select @cmd = N' + '', '''''' + CAST([qcfttabrowid] as nvarchar(40)) + '''''''' + N'' ) ''
  9253.         from ' + @qualname + N' where qcfttabrowid = @qcfttabrowid and tranid = @tranid' 
  9254. insert into dbo.tempcmd(cmdtext) values(@cmd)
  9255. select @rowcnt = @rowcnt + 1
  9256.  
  9257. select @cmd = N'
  9258.         exec @retcode = dbo.sp_MSadd_compensating_cmd @subcriber, @subdb, @compcmd, ' 
  9259.             + CAST(@artid as nvarchar(10)) + N', ' + CAST(@pubid as nvarchar(10)) + N',0,0,'
  9260.             + CAST(@compinsertabempty as nvarchar(4)) + N'
  9261.         if (@@error != 0 or @retcode != 0)
  9262.             return 1 ' 
  9263. insert into dbo.tempcmd(cmdtext) values(@cmd)        
  9264. insert into dbo.tempcmd(cmdtext) values(N'
  9265.     end
  9266. end')
  9267.  
  9268. if (@is_debug = 0)
  9269. begin
  9270.     -- Now we select out the command text pieces in proper order so that our caller,
  9271.     -- xp_execresultset will execute the command that creates the stored procedure.
  9272.     select @dbname = db_name()
  9273.     select @cmd = N'select cmdtext from dbo.tempcmd order by c1'
  9274.     exec @retcode = master..xp_execresultset @cmd, @dbname
  9275.     if (@@error != 0 or @retcode != 0)
  9276.     begin
  9277.         -- roll back the tran
  9278.         rollback tran sp_MSmaketrancftproc
  9279.         return (1)
  9280.     end
  9281.     
  9282.     --
  9283.     -- Check if we create the proc and update sysarticleupdates
  9284.     --
  9285.     select @conflict_proc_id = id from sysobjects where name = @procname and type = 'P '
  9286.     if (@conflict_proc_id is NULL or @conflict_proc_id = 0)
  9287.     begin
  9288.         -- roll back the tran
  9289.         rollback tran sp_MSmaketrancftproc
  9290.         return (1)
  9291.     end
  9292.     else
  9293.     begin
  9294.         update dbo.sysarticleupdates set ins_conflict_proc = @conflict_proc_id
  9295.             where artid = @artid and pubid = @pubid
  9296.         if @@error <> 0
  9297.         begin
  9298.             -- roll back the tran
  9299.             rollback tran sp_MSmaketrancftproc
  9300.             return (1)
  9301.         end
  9302.  
  9303.         -- mark the proc as system object
  9304.         if (@owner in ('dbo','INFORMATION_SCHEMA'))
  9305.         begin
  9306.             exec @retcode = dbo.sp_MS_marksystemobject @procname
  9307.             if (@@error != 0 or @retcode != 0)
  9308.             begin
  9309.                 -- roll back the tran
  9310.                 rollback tran sp_MSmaketrancftproc
  9311.                 return (1)
  9312.             end
  9313.         end
  9314.     end
  9315. end
  9316. else
  9317.     select cmdtext from dbo.tempcmd order by c1
  9318.  
  9319. COMMIT TRAN 
  9320.  
  9321. -- drop the temp tables
  9322. drop table dbo.tempcmd
  9323. drop table #argtab 
  9324. drop table #valtab 
  9325. drop table #paramtab 
  9326. drop table #seltab 
  9327. drop table #sel2tab 
  9328. drop table #decltab 
  9329. drop table #assigntab 
  9330. drop table #where_clausetab 
  9331. drop table #compinstab
  9332. END
  9333. go
  9334. exec dbo.sp_MS_marksystemobject sp_MSmaketrancftproc 
  9335. go
  9336.  
  9337. --------------------------------------------------------------------------------
  9338. --. fn_sqlvarbasetostr
  9339. --------------------------------------------------------------------------------
  9340.  
  9341. if exists (select * from sysobjects
  9342.     where type = 'FN' and name = 'fn_sqlvarbasetostr')
  9343. drop function fn_sqlvarbasetostr
  9344. go
  9345. raiserror('Creating function fn_sqlvarbasetostr', 0,1)
  9346. go
  9347. create function dbo.fn_sqlvarbasetostr (
  9348.     @ssvar sql_variant
  9349. )
  9350. returns nvarchar(4000)
  9351. as
  9352. begin
  9353.     declare @pstrout nvarchar(4000)
  9354.             ,@basetype sysname
  9355.  
  9356.     select @basetype = CAST(SQL_VARIANT_PROPERTY ( @ssvar, 'BaseType' ) as nvarchar(255))
  9357.     if (@ssvar IS NOT NULL and @basetype IS NOT NULL)
  9358.     begin
  9359.         if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'varchar')
  9360.             select @pstrout = N'''' + REPLACE(CAST(@ssvar as nvarchar(4000)), '''', '''''') + N''''
  9361.         else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'nvarchar')
  9362.             select @pstrout = N'N''' + REPLACE(CAST(@ssvar as nvarchar(4000)), '''', '''''') + N''''
  9363.         else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'char')
  9364.             select @pstrout = N'''' + REPLACE(RTRIM(CAST(@ssvar as nvarchar(4000))), '''', '''''') + N''''
  9365.         else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'nchar')
  9366.             select @pstrout = N'N''' + REPLACE(RTRIM(CAST(@ssvar as nvarchar(4000))), '''', '''''') + N''''
  9367.         else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('binary','varbinary'))
  9368.             select @pstrout = master.dbo.fn_varbintohexsubstring(1, CAST(@ssvar as varbinary(8000)), 1, 0)
  9369.         else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('bit','bigint','int','smallint','tinyint','decimal','numeric'))
  9370.             select @pstrout = CAST(@ssvar as nvarchar(40))
  9371.         else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('float','real'))
  9372.             select @pstrout = CONVERT(nvarchar(60), @ssvar, 2)
  9373.         else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('money','smallmoney'))
  9374.             select @pstrout = CONVERT(nvarchar(40), @ssvar, 2)
  9375.         else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) = 'uniqueidentifier')
  9376.             select @pstrout = N'''' + CAST(@ssvar as nvarchar(40)) + N''''
  9377.         else if (lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) in ('datetime','smalldatetime'))
  9378.             select @pstrout = N'''' + CONVERT(nvarchar(40), @ssvar, 112) + N' ' + CONVERT(nvarchar(40), @ssvar, 114) + N''''
  9379.         else
  9380.             select @pstrout = N'''Invalid Datatype' + lower(@basetype collate SQL_Latin1_General_CP1_CS_AS) + N'(' + CAST(@ssvar as nvarchar) + N')'''
  9381.     end
  9382.  
  9383.     -- All done
  9384.     return @pstrout
  9385. end
  9386. go
  9387. exec dbo.sp_MS_marksystemobject fn_sqlvarbasetostr
  9388. go
  9389. grant execute on dbo.fn_sqlvarbasetostr to public
  9390. go
  9391.  
  9392. --------------------------------------------------------------------------------
  9393. --. sp_MSget_col_position
  9394. --------------------------------------------------------------------------------
  9395.  
  9396. if exists (select * from sysobjects
  9397.     where type = 'P' and name = 'sp_MSget_col_position')
  9398. drop procedure sp_MSget_col_position
  9399. go
  9400. raiserror('Creating procedure sp_MSget_col_position ', 0,1)
  9401. go
  9402. create procedure sp_MSget_col_position (
  9403.     @objid int,
  9404.     @columns binary(32),
  9405.     @key     sysname, 
  9406.     @colpos  sysname = NULL output,
  9407.     @art_col int = NULL output,
  9408.     @get_num_col bit = 0,
  9409.     @num_col  int = NULL output,
  9410.     @this_col int = null output
  9411. )
  9412. as
  9413. BEGIN  
  9414.     declare @colname      sysname
  9415.             ,@ccoltype     sysname
  9416.             ,@rc           int
  9417.     
  9418.     select @num_col = 0
  9419.     --
  9420.     -- Use a cursor to walk through the columns
  9421.     --
  9422.     DECLARE #hCColid CURSOR LOCAL FAST_FORWARD FOR 
  9423.         select colid from syscolumns where id = @objid order by colid asc
  9424.     OPEN #hCColid
  9425.     FETCH #hCColid INTO @this_col
  9426.     WHILE (@@fetch_status <> -1)
  9427.     begin
  9428.         exec @rc = dbo.sp_MSget_colinfo @objid, @this_col, @columns, 1, @colname output, @ccoltype output
  9429.         if @rc = 0
  9430.         begin
  9431.             select @num_col = @num_col + 1
  9432.             -- If @get_num_col is 1, we just need the number of columns in the partition.
  9433.             if (@get_num_col != 1) and (@colname = @key)
  9434.             begin
  9435.                 select @colpos = 'c' + convert(varchar(4), @this_col)
  9436.                         ,@art_col = @num_col
  9437.                 break
  9438.             end
  9439.         end
  9440.         FETCH #hCColid INTO @this_col
  9441.     end
  9442.     close #hCColid
  9443.     deallocate #hCColid
  9444.     return 0
  9445. END
  9446. go
  9447. exec dbo.sp_MS_marksystemobject sp_MSget_col_position
  9448. go
  9449.  
  9450. --------------------------------------------------------------------------------
  9451. --. sp_scriptpkwhereclause
  9452. --------------------------------------------------------------------------------
  9453.  
  9454. if exists (select * from sysobjects
  9455.     where type = 'P' and name = 'sp_scriptpkwhereclause')
  9456. drop procedure sp_scriptpkwhereclause
  9457. go
  9458. raiserror('Creating procedure sp_scriptpkwhereclause', 0,1)
  9459. go
  9460. create procedure sp_scriptpkwhereclause 
  9461. (
  9462. @src_objid int, 
  9463. @pkcolumns binary(32),
  9464. @prefix nvarchar(10) = N'@pkc',
  9465. @artcolumns binary(32) = NULL,
  9466. @mode tinyint = 1 -- 1 = use article ordering, 2 = column ordering
  9467. )
  9468. as
  9469. begin
  9470.     declare @this_col int
  9471.     declare @art_col int
  9472.     declare @spacer nvarchar(10)
  9473.     declare @isset int
  9474.     declare @cmd nvarchar(4000)
  9475.  
  9476.     declare @modeartorder tinyint
  9477.                 ,@modecolorder tinyint
  9478.  
  9479.     select @modeartorder = 1
  9480.             ,@modecolorder = 2
  9481.             ,@art_col = 0
  9482.             ,@spacer = N' '
  9483.             ,@cmd = N'where'
  9484.  
  9485.     if (@mode not in (@modeartorder, @modecolorder))
  9486.         return 1
  9487.  
  9488.     -- create WHERE clause
  9489.     DECLARE hCColid CURSOR LOCAL FAST_FORWARD FOR 
  9490.     select colid from syscolumns where id = @src_objid order by colid asc
  9491.  
  9492.     OPEN hCColid
  9493.  
  9494.     FETCH hCColid INTO @this_col
  9495.  
  9496.     WHILE (@@fetch_status <> -1)
  9497.     begin
  9498.         if EXISTS (select name from syscolumns where id=@src_objid and @this_col=colid)
  9499.         begin
  9500.             -- If @artcolumns is not null, it is called from 
  9501.             -- sp_scriptxupdproc or sp_scriptxdelproc
  9502.             -- Use counter in article column bitmap
  9503.             -- Otherwise use counter in pk bitmap
  9504.             if @artcolumns is not null
  9505.             begin
  9506.                 exec @isset = dbo.sp_isarticlecolbitset @this_col, @artcolumns
  9507.                 if @isset != 0
  9508.                     select @art_col = @art_col + 1
  9509.             end
  9510.             exec @isset = dbo.sp_isarticlecolbitset @this_col, @pkcolumns
  9511.             if @isset != 0 
  9512.             begin
  9513.                 if @artcolumns is null
  9514.                     select @art_col = @art_col + 1
  9515.             select @cmd = @cmd + @spacer + QUOTENAME(col_name( @src_objid, @this_col)) + N' = ' 
  9516.             --
  9517.             -- script the var assignment based on mode
  9518.             --
  9519.             if (@mode = @modeartorder)
  9520.                     select @cmd = @cmd + @prefix + convert( nvarchar, @art_col ) 
  9521.                 else
  9522.                     select @cmd = @cmd + @prefix + convert( nvarchar, @this_col ) 
  9523.                 select @spacer = N' and '
  9524.                 if len( @cmd ) > 3000
  9525.                 begin
  9526.                     insert into #proctext(procedure_text) values( @cmd )
  9527.                     select @cmd = N''
  9528.                 end
  9529.             end
  9530.         end
  9531.         FETCH hCColid INTO @this_col
  9532.     end
  9533.     CLOSE hCColid
  9534.     DEALLOCATE hCColid
  9535.  
  9536.     insert into #proctext(procedure_text) values( @cmd )
  9537. end
  9538. go
  9539. EXEC dbo.sp_MS_marksystemobject sp_scriptpkwhereclause
  9540. GO
  9541. grant exec on dbo.sp_scriptpkwhereclause to public
  9542. go
  9543.  
  9544. --------------------------------------------------------------------------------
  9545. --. sp_MSscript_pkvar_assignment
  9546. --------------------------------------------------------------------------------
  9547.  
  9548. if exists (select * from sysobjects
  9549.     where type = 'P' and name = 'sp_MSscript_pkvar_assignment')
  9550. drop procedure sp_MSscript_pkvar_assignment
  9551. go
  9552. raiserror('Creating procedure sp_MSscript_pkvar_assignment', 0,1)
  9553. go
  9554. create procedure sp_MSscript_pkvar_assignment
  9555. (
  9556.     @objid          int,
  9557.     @columns      binary(32), 
  9558.     @indent       int = 0,
  9559.     @identity_col sysname = NULL, -- Not null value used by trigger scripting
  9560.     @ts_col       sysname = NULL,  -- Not null value used by trigger scripting
  9561.     @primary_key_bitmap varbinary(4000) = null, -- NULL when synctran processing
  9562.     @fisqueuedpub bit = 0  -- 1 = processing a queued publication on publisher
  9563. )
  9564. as
  9565. begin
  9566.     -- This stored procedure will assign the '_old' var to new var
  9567.     -- based on @bitmap. This is to avoid using case statement
  9568.     -- in the where clause in the synctran pub proc, which
  9569.     -- will cause a table scan.
  9570.     declare @cmd          nvarchar(4000)
  9571.         ,@spacer       nvarchar(20)
  9572.         ,@indkey       int
  9573.         ,@indid        int
  9574.         ,@this_col     int
  9575.         ,@col          sysname
  9576.         ,@qualname     nvarchar(512)
  9577.         ,@column          nvarchar(255)
  9578.         ,@key          sysname
  9579.         ,@src_cols      int
  9580.         ,@total_col        int
  9581.         ,@fcreatedcolmap    bit
  9582.         ,@art_col int -- relative position of column
  9583.     declare @colmap table (relativeorder int identity(1,1), colid int)
  9584.  
  9585.     select @spacer = N'select '
  9586.         ,@cmd = N''
  9587.         ,@indkey = 1
  9588.         ,@indid = 0
  9589.         ,@fcreatedcolmap = 0
  9590.     exec sp_MSget_qualified_name @objid, @qualname OUTPUT
  9591.     select @src_cols = max(colid)
  9592.             ,@total_col = count(colid)
  9593.         from syscolumns where id = @objid
  9594.     exec dbo.sp_MSpad_command @cmd output, @indent
  9595.     exec dbo.sp_MSflush_command @cmd output, 1, @indent
  9596.  
  9597.     if @primary_key_bitmap is null
  9598.     begin
  9599.         exec @indid = dbo.sp_MStable_has_unique_index @objid
  9600.         if @indid is null
  9601.         begin
  9602.             raiserror('Debug: Cannot find unique index', 16, -1)
  9603.             return (1)
  9604.         end
  9605.     end
  9606.  
  9607.     --
  9608.     -- check if column Id match relative column order
  9609.     -- for trigger scripting
  9610.     --
  9611.     if ((@total_col < @src_cols) and 
  9612.         (@columns is null) and (@primary_key_bitmap is not null))
  9613.     begin
  9614.         --
  9615.         -- this table may have altered columns, so when we need to 
  9616.         -- set a mapping for using the bitmaps properly as the bitmap
  9617.         -- always refers relative column order
  9618.         --
  9619.         insert into @colmap (colid)
  9620.             select colid from syscolumns where id = @objid order by colid
  9621.         if (@@error != 0)
  9622.         begin
  9623.             raiserror('Could not create column mapping', 16, -1)
  9624.             return (1)
  9625.         end
  9626.         select @fcreatedcolmap = 1
  9627.     end
  9628.  
  9629.     while (1=1)
  9630.     begin
  9631.         if @primary_key_bitmap is null 
  9632.         begin
  9633.             select @key = index_col(@qualname, @indid, @indkey)
  9634.             if @key is null
  9635.                 break
  9636.             exec dbo.sp_MSget_col_position @objid, @columns, @key, @col output, 0, NULL, @this_col output
  9637.         end
  9638.         else
  9639.         begin
  9640.             exec dbo.sp_MSget_map_position @primary_key_bitmap, @indkey, @col output, @this_col output
  9641.             if @this_col is null
  9642.                 break
  9643.  
  9644.                 --
  9645.                 -- set the actual column id for this relative order in the PK bitmap if necessary
  9646.                 --
  9647.             if (@fcreatedcolmap = 1)
  9648.             begin
  9649.                 select @art_col = @this_col
  9650.                 select @this_col = colid
  9651.                     ,@col = 'c' + convert(sysname, colid) 
  9652.                 from @colmap 
  9653.                 where relativeorder = @art_col 
  9654.             end
  9655.             else
  9656.             begin
  9657.                 select @art_col = NULL
  9658.             end
  9659.  
  9660.             -- Get column name
  9661.             exec dbo.sp_MSget_colinfo @objid, @this_col, @columns, 0, @key output
  9662.         end
  9663.         select @indkey = @indkey + 1
  9664.         --
  9665.         -- check if identity/timestamp column were specified
  9666.         -- for skipping during subscriber trigger scripting
  9667.         --
  9668.         if @key in (@identity_col, @ts_col)
  9669.             continue
  9670.         --
  9671.         -- If we are scripting on publisher 
  9672.         --
  9673.         if (@primary_key_bitmap is null)
  9674.         begin
  9675.             declare @isset int
  9676.             --
  9677.             -- skip column if not replicated
  9678.             --
  9679.             exec @isset = dbo.sp_isarticlecolbitset @this_col, @columns
  9680.             if (@isset != 1)
  9681.                 continue
  9682.             --
  9683.             -- skip timestamp processing for queued
  9684.             --
  9685.             if ((@fisqueuedpub = 1) and 
  9686.                 exists (select name from syscolumns 
  9687.                     where id = @objid and colid = @this_col and xtype = 189))
  9688.                 continue
  9689.         end
  9690.  
  9691.         select @cmd = @spacer + N'@c' + convert(nvarchar(10), @this_col)
  9692.  
  9693.         -- Get the new values for the columns in primary key.
  9694.         exec dbo.sp_MSget_synctran_column 
  9695.             @ts_col = null,
  9696.             @op_type = null , -- 'ins, 'upd', 'del'
  9697.             @is_new = null,
  9698.             @primary_key_bitmap = null,
  9699.             @colname = null,
  9700.             @this_col = @this_col,
  9701.             @column = @column output,
  9702.             @from_proc = 0,
  9703.             @coltype = null,
  9704.             @type = 'pk_var',
  9705.             @art_col = @art_col
  9706.             select @cmd = @cmd + N' = ' + @column 
  9707.             select @spacer = ',
  9708.     '
  9709.  
  9710.         -- flush command if necessary
  9711.         exec dbo.sp_MSflush_command @cmd output, 1, @indent
  9712.     end
  9713.  
  9714. end
  9715. go
  9716. EXEC dbo.sp_MS_marksystemobject sp_MSscript_pkvar_assignment
  9717. GO
  9718. grant exec on dbo.sp_MSscript_pkvar_assignment to public
  9719. go
  9720.  
  9721. -- ------------------------------------------------------------------
  9722. -- Concurrent updates
  9723. -- ------------------------------------------------------------------
  9724.  
  9725. --------------------------------------------------------------------------------
  9726. --. sp_repldeletequeuedtran
  9727. --------------------------------------------------------------------------------
  9728.  
  9729. if exists (select * from sysobjects
  9730.     where type = 'P' and name = 'sp_repldeletequeuedtran')
  9731. drop procedure sp_repldeletequeuedtran
  9732. go
  9733. raiserror('Creating procedure sp_repldeletequeuedtran', 0,1)
  9734. go
  9735. create proc sp_repldeletequeuedtran 
  9736. (
  9737.     @publisher sysname
  9738.     ,@publisher_db sysname
  9739.     ,@publication sysname
  9740.     ,@tranid sysname
  9741.     ,@orderkeylow bigint
  9742.     ,@orderkeyhigh bigint
  9743. )
  9744. as
  9745. begin
  9746.     declare @retcode int
  9747.     set nocount on
  9748.     --
  9749.     -- Security check
  9750.     --
  9751.     exec @retcode = dbo.sp_MSreplcheck_subscribe
  9752.     if @@error != 0 or @retcode != 0
  9753.         return 1
  9754.     --
  9755.     -- validate inputs
  9756.     --
  9757.     if (@tranid is null 
  9758.             or @orderkeylow is null or @orderkeylow = 0 
  9759.             or @orderkeyhigh is null or @orderkeyhigh = 0
  9760.             or @orderkeyhigh < @orderkeylow)
  9761.         return 1
  9762.     --
  9763.     -- begin local transaction
  9764.     --
  9765.     begin transaction sp_repldeletequeuedtran
  9766.     save transaction sp_repldeletequeuedtran
  9767.     --
  9768.     -- delete rows from MSreplication_queue
  9769.     --
  9770.     delete dbo.MSreplication_queue 
  9771.     where publisher = UPPER(@publisher)
  9772.         and publisher_db = @publisher_db
  9773.         and publication = @publication
  9774.         and tranid = @tranid 
  9775.         and orderkey between @orderkeylow and @orderkeyhigh
  9776.     if (@@error != 0)
  9777.         goto Error
  9778.     --
  9779.     -- delete row from MSrepl_queuedtraninfo
  9780.     --
  9781.     delete dbo.MSrepl_queuedtraninfo 
  9782.     where publisher = UPPER(@publisher)
  9783.         and publisher_db = @publisher_db
  9784.         and publication = @publication
  9785.         and tranid = @tranid 
  9786.     if (@@error != 0)
  9787.         goto Error
  9788.     --
  9789.     -- commit local transaction
  9790.     --
  9791.     commit transaction sp_repldeletequeuedtran
  9792.     --
  9793.     -- all done
  9794.     --
  9795.     return 0
  9796.  
  9797. Error:
  9798.     rollback transaction sp_repldeletequeuedtran
  9799.     commit transaction
  9800.     return 1
  9801. end
  9802. go
  9803. exec dbo.sp_MS_marksystemobject sp_repldeletequeuedtran
  9804. go
  9805. grant execute on dbo.sp_repldeletequeuedtran to public
  9806. go
  9807.  
  9808. --------------------------------------------------------------------------------
  9809. --. sp_replsqlqgetrows
  9810. --------------------------------------------------------------------------------
  9811.  
  9812. if exists (select * from sysobjects
  9813.     where type = 'P' and name = 'sp_replsqlqgetrows')
  9814. drop procedure sp_replsqlqgetrows
  9815. go
  9816. raiserror('Creating procedure sp_replsqlqgetrows', 0,1)
  9817. go
  9818. create proc sp_replsqlqgetrows 
  9819. (
  9820.     @publisher sysname
  9821.     ,@publisherdb sysname
  9822.     ,@publication sysname
  9823.     ,@batchsize int = 1000
  9824. )
  9825. as
  9826. begin
  9827.     declare @retcode int
  9828.     set nocount on
  9829.     --
  9830.     -- Security check
  9831.     --
  9832.     exec @retcode = dbo.sp_MSreplcheck_subscribe
  9833.     if @@error != 0 or @retcode != 0
  9834.         return 1
  9835.     --
  9836.     -- does the queue table exist
  9837.     --
  9838.     if exists (select * from dbo.sysobjects where name = 'MSreplication_queue')
  9839.     begin
  9840.         declare @totcommandcount bigint
  9841.                 ,@trancount bigint
  9842.         --
  9843.         -- does the tran info table exist
  9844.         --
  9845.         if not exists (select * from dbo.sysobjects where name = 'MSrepl_queuedtraninfo')
  9846.         begin
  9847.             --
  9848.             -- tran info table does not exist - create and populate it
  9849.             --
  9850.             exec @retcode = sp_MScreate_sub_tables
  9851.                 @tran_sub_table = 0,
  9852.                 @property_table = 0,
  9853.                 @sqlqueue_table = 1
  9854.             if  (@@error != 0 or @retcode != 0)
  9855.                 return 1
  9856.         end    
  9857.         --
  9858.         -- At this point both queue table and tran info table exist
  9859.         -- check the command count
  9860.         --
  9861.         select @totcommandcount = sum(commandcount)
  9862.             ,@trancount = count(tranid)
  9863.         from dbo.MSrepl_queuedtraninfo with (READPAST)
  9864.         where publisher = UPPER(@publisher)
  9865.             and publisher_db = @publisherdb 
  9866.             and publication = @publication
  9867.  
  9868.         if (@trancount > 1 and @totcommandcount > @batchsize)
  9869.         begin
  9870.             --
  9871.             -- prepare a list of transactions to read
  9872.             --
  9873.             declare @tranid sysname
  9874.                     ,@batchcount bigint
  9875.                     ,@curtrancommandcount bigint
  9876.             declare @trantab table (tranid sysname primary key)
  9877.  
  9878.             select @batchcount = 0
  9879.             declare #htcdataseq cursor local for
  9880.                 select tranid, commandcount
  9881.                 from dbo.MSrepl_queuedtraninfo with (READPAST) 
  9882.                 where publisher = UPPER(@publisher) 
  9883.                     and publisher_db = @publisherdb 
  9884.                     and publication = @publication
  9885.                 order by maxorderkey asc
  9886.             open #htcdataseq
  9887.             fetch #htcdataseq into @tranid, @curtrancommandcount
  9888.             if (@@error != 0)
  9889.                 return 1
  9890.             while (@@fetch_status != -1)
  9891.             begin
  9892.                 --
  9893.                 -- Are we done
  9894.                 --
  9895.                 if (@batchcount > @batchsize)
  9896.                 begin
  9897.                     --
  9898.                     -- we are done selecting the transactions to process
  9899.                     --
  9900.                     break
  9901.                 end
  9902.                 else
  9903.                 begin
  9904.                     --
  9905.                     -- include this transaction
  9906.                     -- update the batch counter
  9907.                     --
  9908.                     insert into @trantab (tranid) values (@tranid)
  9909.                     if (@@error != 0)
  9910.                         return 1
  9911.                     select @batchcount = @batchcount + @curtrancommandcount
  9912.                 end
  9913.                 --
  9914.                 -- fetch next transaction to process
  9915.                 --
  9916.                 fetch #htcdataseq into @tranid, @curtrancommandcount
  9917.             end
  9918.             close #htcdataseq
  9919.             deallocate #htcdataseq
  9920.             if (@@error != 0)
  9921.                 return 1
  9922.             --
  9923.             -- do the join for the select transactions
  9924.             -- select the transactions in the order they were committed (maxorderkey ascending).
  9925.             -- for each transaction - the commands are ordered using orderkey (ascending)
  9926.             --
  9927.             select q.tranid, q.datalen, q.data, q.commandtype, q.insertdate, q.orderkey, q.cmdstate 
  9928.             from (dbo.MSreplication_queue as q with (READPAST) 
  9929.                 join (dbo.MSrepl_queuedtraninfo as t with (READPAST)
  9930.                     join @trantab as tt
  9931.                     on t.tranid = tt.tranid collate database_default) 
  9932.                 on q.publisher = t.publisher
  9933.                     and q.publisher_db = t.publisher_db 
  9934.                     and q.publication = t.publication
  9935.                     and q.tranid = t.tranid)
  9936.             where t.publisher = UPPER(@publisher)
  9937.                 and t.publisher_db = @publisherdb 
  9938.                 and t.publication = @publication
  9939.             order by t.maxorderkey asc, q.orderkey asc
  9940.         end
  9941.         else
  9942.         begin
  9943.             --
  9944.             -- do the join for all the transactions
  9945.             -- select the transactions in the order they were committed (maxorderkey ascending).
  9946.             -- for each transaction - the commands are ordered using orderkey (ascending)
  9947.             --
  9948.             select q.tranid, q.datalen, q.data, q.commandtype, q.insertdate, q.orderkey, q.cmdstate 
  9949.             from (dbo.MSreplication_queue as q with (READPAST) 
  9950.                 join dbo.MSrepl_queuedtraninfo as t with (READPAST)
  9951.                 on q.publisher = t.publisher
  9952.                     and q.publisher_db = t.publisher_db 
  9953.                     and q.publication = t.publication
  9954.                     and q.tranid = t.tranid)
  9955.             where t.publisher = UPPER(@publisher)
  9956.                 and t.publisher_db = @publisherdb 
  9957.                 and t.publication = @publication
  9958.             order by t.maxorderkey asc, q.orderkey asc
  9959.         end
  9960.     end
  9961.     else
  9962.     begin
  9963.         --
  9964.         -- Queue table does not exist
  9965.         -- create empty rowset
  9966.         --
  9967.         declare @nomesgs TABLE (tranid sysname, datalen int, data varbinary(8000),
  9968.             commandtype int, insertdate datetime, orderkey bigint, cmdstate bit)
  9969.         select * from @nomesgs
  9970.     end    
  9971.     --
  9972.     -- check error
  9973.     --
  9974.     if (@@error != 0)
  9975.         return 1
  9976.     --
  9977.     -- All done
  9978.     --
  9979.     return 0
  9980. end
  9981. go
  9982. exec dbo.sp_MS_marksystemobject sp_replsqlqgetrows
  9983. go
  9984. grant execute on dbo.sp_replsqlqgetrows to public
  9985. go
  9986.  
  9987. --------------------------------------------------------------------------------
  9988. --. sp_subscription_cleanup
  9989. --------------------------------------------------------------------------------
  9990.  
  9991. if exists (select * from sysobjects
  9992.     where type = 'P' and name = 'sp_subscription_cleanup')
  9993. drop procedure sp_subscription_cleanup
  9994. go
  9995. raiserror('Creating procedure sp_subscription_cleanup', 0,1)
  9996. GO
  9997. CREATE PROCEDURE sp_subscription_cleanup (
  9998.     @publisher        sysname,
  9999.     @publisher_db    sysname,
  10000.     @publication    sysname = NULL,
  10001.     @reserved        nvarchar(10) = NULL
  10002. )
  10003. AS
  10004. BEGIN
  10005.  
  10006.     declare @object_name sysname
  10007.             ,@object_type char(2)
  10008.             ,@independent_agent bit
  10009.             ,@retcode int
  10010.             ,@synctran_bit int
  10011.             ,@parent_obj int
  10012.             ,@object_id int
  10013.             ,@cmd nvarchar(4000)
  10014.  
  10015.     select @synctran_bit            = 256
  10016.  
  10017.     /*
  10018.     ** Security Check
  10019.     */
  10020.  
  10021.     EXEC @retcode = dbo.sp_MSreplcheck_subscribe
  10022.     IF @@ERROR <> 0 or @retcode <> 0
  10023.         RETURN(1)
  10024.  
  10025.     if @publication = '' OR @publication is NULL
  10026.         select @independent_agent = 0
  10027.     else
  10028.         select @independent_agent = 1
  10029.  
  10030.     IF exists (select name from sysobjects where name = 'MSreplication_objects')
  10031.     BEGIN
  10032.         declare object_cursor CURSOR LOCAL FAST_FORWARD for 
  10033.             select DISTINCT object_name, object_type from MSreplication_objects o
  10034.                     where (UPPER(o.publisher) = UPPER(@publisher) and
  10035.                         o.publisher_db = @publisher_db and
  10036.                         o.publication = @publication) or
  10037.                         @reserved = 'drop_all'
  10038.  
  10039.         OPEN object_cursor
  10040.         FETCH object_cursor INTO @object_name, @object_type
  10041.          WHILE (@@fetch_status <> -1)
  10042.               BEGIN
  10043.                   IF @object_type = 'T' 
  10044.                   begin
  10045.                     select @parent_obj = NULL
  10046.                     select @parent_obj = parent_obj, @object_id = id from
  10047.                         sysobjects where name = @object_name 
  10048.                     if @parent_obj is not null
  10049.                     begin
  10050.                         -- Unmark synctran bit
  10051.                         update sysobjects set replinfo = replinfo & ~@synctran_bit where 
  10052.                             id = @parent_obj and
  10053.                             (replinfo & @synctran_bit) <> 0
  10054.                         IF @@ERROR <> 0 
  10055.                             GOTO UNDO
  10056.                         exec @retcode = dbo.sp_MSdrop_object 
  10057.                             @object_id = @object_id
  10058.                         if @retcode <> 0 or @@error <> 0
  10059.                             goto UNDO
  10060.  
  10061.                         -- Clean up identity range entry
  10062.                         -- Since we only support one trigger per subscriber table
  10063.                         -- we assume identity range row can not be reused by multiple
  10064.                         -- subscriptions.
  10065.                         IF EXISTS(select * from sysobjects where type='U' and name = 'MSsub_identity_range')
  10066.                         BEGIN
  10067.                             if exists (select * from MSsub_identity_range where objid = @parent_obj)
  10068.                             begin
  10069.                                 -- Drop the identity range constraits.
  10070.                                 exec @retcode = dbo.sp_MSreseed
  10071.                                     @objid =  @parent_obj,
  10072.                                     -- range or seed can be anything
  10073.                                     @next_seed = 10,
  10074.                                     @range = 10,
  10075.                                     @is_publisher = -1,
  10076.                                     @check_only = 1,
  10077.                                     @drop_only = 1
  10078.                                 IF @retcode <> 0 or @@ERROR <> 0 
  10079.                                     GOTO UNDO
  10080.  
  10081.                                 delete MSsub_identity_range where objid = @parent_obj
  10082.                                 IF @@ERROR <> 0 
  10083.                                     GOTO UNDO
  10084.                             end
  10085.  
  10086.                             IF NOT EXISTS (SELECT * FROM MSsub_identity_range)
  10087.                             BEGIN
  10088.                                 DROP TABLE MSsub_identity_range
  10089.                                 IF @@ERROR <> 0 
  10090.                                     GOTO UNDO
  10091.                             END
  10092.                         END
  10093.                     end
  10094.                   end
  10095.                   delete from MSreplication_objects where object_name=@object_name
  10096.                   FETCH object_cursor INTO @object_name, @object_type
  10097.               END
  10098.         CLOSE object_cursor
  10099.         DEALLOCATE object_cursor
  10100.         
  10101.         if not exists (select * from MSreplication_objects) 
  10102.         begin
  10103.             drop table MSreplication_objects
  10104.             IF @@ERROR <> 0 
  10105.                 GOTO UNDO
  10106.         end
  10107.         
  10108.     END
  10109.  
  10110.     --
  10111.     -- cleanup queued conflict tables
  10112.     --
  10113.     IF exists (select name from dbo.sysobjects where name = 'MSsubscription_agents')
  10114.     BEGIN
  10115.         declare        @agent_id int
  10116.                     ,@cft_table sysname
  10117.                     ,@owner sysname
  10118.  
  10119.         --
  10120.         -- first get the agent(s) for this queued subscription(s) and 
  10121.         -- 
  10122.         declare #agent_cursor CURSOR LOCAL FAST_FORWARD for 
  10123.             select id from dbo.MSsubscription_agents 
  10124.             where ((UPPER(publisher) = UPPER(@publisher) and 
  10125.                     publisher_db = @publisher_db and 
  10126.                     publication = @publication) or (@reserved = 'drop_all')) and
  10127.                     update_mode in (2,3,4,5)
  10128.  
  10129.         open #agent_cursor
  10130.         fetch #agent_cursor into @agent_id
  10131.         while (@@fetch_status != -1)
  10132.         begin
  10133.             --
  10134.             -- drop the conflict table for each article in this subscription
  10135.             --
  10136.             if exists (select name from dbo.sysobjects where name = 'MSsubscription_articles')
  10137.             begin
  10138.             
  10139.                 declare #object_cursor CURSOR LOCAL FAST_FORWARD for 
  10140.                     select owner, cft_table from dbo.MSsubscription_articles
  10141.                     where agent_id = @agent_id
  10142.  
  10143.                 OPEN #object_cursor
  10144.                 FETCH #object_cursor INTO @owner, @cft_table
  10145.                 WHILE (@@fetch_status != -1)
  10146.                 BEGIN
  10147.                     --
  10148.                     -- drop the conflict table(s) for this article - ignore errors
  10149.                     --
  10150.                     select @cmd = case 
  10151.                         when (@owner IS NULL) then
  10152.                             N'if exists (select * from dbo.sysobjects where name = N''' + 
  10153.                             master.dbo.fn_MSgensqescstr(@cft_table) collate database_default + ''') drop table ' + 
  10154.                             quotename(master.dbo.fn_MSgensqescstr(@cft_table)) collate database_default
  10155.                         else
  10156.                             N'if exists (select * from dbo.sysobjects where name = N''' + 
  10157.                             master.dbo.fn_MSgensqescstr(@cft_table) collate database_default + ''') drop table ' + 
  10158.                             quotename(master.dbo.fn_MSgensqescstr(@owner)) collate database_default + N'.' +
  10159.                             quotename(master.dbo.fn_MSgensqescstr(@cft_table)) collate database_default
  10160.                         end
  10161.                     execute ( @cmd )
  10162.  
  10163.                     -- get next row
  10164.                     FETCH #object_cursor INTO @owner, @cft_table
  10165.                 END
  10166.                 CLOSE #object_cursor
  10167.                 DEALLOCATE #object_cursor
  10168.  
  10169.                 --
  10170.                 -- delete entries from MSsubscription_articles for this agent id
  10171.                 --
  10172.                 delete dbo.MSsubscription_articles where agent_id = @agent_id
  10173.  
  10174.                 --
  10175.                 -- drop MSsubscription_articles if empty (should we do it)
  10176.                 -- 
  10177.                 IF NOT EXISTS (SELECT * FROM dbo.MSsubscription_articles)
  10178.                 BEGIN
  10179.                     DROP TABLE dbo.MSsubscription_articles
  10180.                     IF @@ERROR != 0 
  10181.                         GOTO UNDO
  10182.                 END
  10183.             end
  10184.  
  10185.             --
  10186.             -- get the next agent
  10187.             --
  10188.             fetch #agent_cursor into @agent_id
  10189.         end
  10190.         close #agent_cursor
  10191.         deallocate #agent_cursor
  10192.     END
  10193.  
  10194.     --
  10195.     -- clean discarded queued transactions
  10196.     --
  10197.     if exists (select name from dbo.sysobjects where name = 'MSreplication_queue')
  10198.     begin
  10199.         delete dbo.MSreplication_queue
  10200.         where (publisher = UPPER(@publisher) and 
  10201.                 publisher_db = @publisher_db and 
  10202.                 publication = @publication) or 
  10203.                 @reserved = 'drop_all'
  10204.     end
  10205.     if exists (select name from dbo.sysobjects where name = 'MSrepl_queuedtraninfo')
  10206.     begin
  10207.         delete dbo.MSrepl_queuedtraninfo
  10208.         where (publisher = UPPER(@publisher) and 
  10209.                 publisher_db = @publisher_db and 
  10210.                 publication = @publication) or 
  10211.                 @reserved = 'drop_all'
  10212.     end
  10213.     
  10214.     IF exists (select name from sysobjects where name = 'MSreplication_subscriptions')
  10215.     BEGIN
  10216.     delete from MSreplication_subscriptions 
  10217.         where (UPPER(publisher) = UPPER(@publisher) AND
  10218.               publisher_db = @publisher_db AND
  10219.               -- Drop the subscription as long as the publication name matches even if
  10220.               -- the publication is not independent agent
  10221.               -- This behaviour is expected by sp_droppullsubscription
  10222.               -- -- independent_agent = @independent_agent and 
  10223.               ((@independent_agent=0 and independent_agent = 0) or 
  10224.               publication = @publication))
  10225.               or @reserved = 'drop_all'
  10226.  
  10227.         IF NOT EXISTS (SELECT * FROM MSreplication_subscriptions)
  10228.         BEGIN
  10229.             DROP TABLE MSreplication_subscriptions
  10230.             IF @@ERROR <> 0 
  10231.                 GOTO UNDO
  10232.         END
  10233.     END
  10234.  
  10235.  
  10236.     IF exists (select name from sysobjects where name = 'MSsubscription_agents')
  10237.     BEGIN
  10238.         delete from MSsubscription_agents
  10239.         where (UPPER(publisher) = UPPER(@publisher) AND
  10240.               publisher_db = @publisher_db AND
  10241.               -- Drop the subscription as long as the publication name matches even if
  10242.               -- the publication is not independent agent
  10243.               -- This behaviour is expected by sp_droppullsubscription
  10244.               (publication = @publication or
  10245.                (@independent_agent=0 and publication = N'ALL')))
  10246.               or @reserved = 'drop_all'
  10247.  
  10248.         -- Delete the agent entry if no corresponding rows found in MSreplication_subscription
  10249.         -- table.
  10250.         -- This is to cleanup share agent entry.
  10251.         -- This behaviour is expected by sp_droppullsubscription
  10252.         if object_id('MSreplication_subscriptions') is not null
  10253.         begin
  10254.             if not exists (select * from MSreplication_subscriptions s where
  10255.                     s.publisher = @publisher and
  10256.                     s.publisher_db = @publisher_db and
  10257.                     s.independent_agent = 0)
  10258.                 delete from MSsubscription_agents where
  10259.                     publisher = @publisher and
  10260.                     publisher_db = @publisher_db and
  10261.                     publication = N'ALL'
  10262.         end
  10263.         else
  10264.             delete  MSsubscription_agents
  10265.  
  10266.         IF NOT EXISTS (SELECT * FROM MSsubscription_agents)
  10267.         BEGIN
  10268.             DROP TABLE MSsubscription_agents
  10269.             IF @@ERROR <> 0 
  10270.                 GOTO UNDO
  10271.         END
  10272.     END
  10273.  
  10274.     IF EXISTS(select * from sysobjects where type=N'U' and name = 'MSsubscription_properties')
  10275.     BEGIN
  10276.         DELETE FROM MSsubscription_properties 
  10277.         WHERE (UPPER(publisher) = UPPER(@publisher)    AND
  10278.         publisher_db  = @publisher_db AND
  10279.         publication = @publication) 
  10280.         or @reserved = 'drop_all'
  10281.  
  10282.         IF @@ERROR <> 0 
  10283.             GOTO UNDO
  10284.  
  10285.         IF NOT EXISTS (SELECT * FROM MSsubscription_properties)
  10286.         BEGIN
  10287.             exec @retcode = dbo.sp_MSsub_cleanup_prop_table
  10288.             IF @@ERROR <> 0 or @retcode <> 0
  10289.                 GOTO UNDO
  10290.         END
  10291.     END
  10292.  
  10293.     -- Ignore errors.
  10294.     exec dbo.sp_MSsub_cleanup_orphans
  10295.     
  10296.     return (0)
  10297.             
  10298. UNDO:
  10299.     return(1)
  10300. END
  10301. GO
  10302. exec dbo.sp_MS_marksystemobject sp_subscription_cleanup 
  10303. go
  10304.  
  10305. --------------------------------------------------------------------------------
  10306. --. sp_MSreset_queue
  10307. --------------------------------------------------------------------------------
  10308.  
  10309. if exists (select * from sysobjects
  10310.     where type = 'P' and name = 'sp_MSreset_queue')
  10311. drop procedure sp_MSreset_queue
  10312. go
  10313. raiserror('Creating procedure sp_MSreset_queue', 0,1)
  10314. GO
  10315. CREATE PROCEDURE sp_MSreset_queue (
  10316.     @publisher      sysname,                    -- publishing server name
  10317.     @publisher_db   sysname,                    -- publishing database name. 
  10318.     @publication    sysname,                    -- publication name,
  10319.     @artid         int)
  10320. as
  10321. begin
  10322.     declare @subserver sysname
  10323.             ,@subdbname sysname
  10324.             ,@queue_id  sysname
  10325.             ,@update_mode int
  10326.             ,@retcode smallint
  10327.             ,@vbartid varbinary(20)
  10328.             ,@queue_server sysname
  10329.  
  10330.     set nocount on
  10331.     --
  10332.     -- Security Check
  10333.     --
  10334.     EXEC @retcode = dbo.sp_MSreplcheck_subscribe
  10335.     IF @@ERROR <> 0 or @retcode <> 0
  10336.         RETURN(1)
  10337.  
  10338.     select     @subserver = @@servername, 
  10339.             @subdbname = db_name(),
  10340.             @update_mode = update_mode, 
  10341.             @queue_id = queue_id,
  10342.             @queue_server = queue_server
  10343.     from MSsubscription_agents
  10344.         where UPPER(publisher) = UPPER(@publisher)
  10345.             and publisher_db =  @publisher_db
  10346.             and publication = @publication
  10347.  
  10348.     if (@update_mode in (2,3))
  10349.     begin
  10350.         --
  10351.         -- MSMQ processing
  10352.         -- prefix the queue_id with queue server in direct format
  10353.         -- and then perform the queue reset
  10354.         --                        
  10355.         select @queue_id = N'DIRECT=OS:' + @queue_server + N'\PRIVATE$\' + @queue_id
  10356.         
  10357.         begin distributed tran
  10358.         exec @retcode = master.dbo.xp_resetqueue @queue_id, @subserver, 
  10359.                             @subdbname, @publication, @artid
  10360.         if (@retcode != 0 or @@error != 0)
  10361.         begin
  10362.             if (@@trancount > 0)
  10363.                 rollback tran
  10364.             return (1)    
  10365.         end
  10366.     end
  10367.     else if (@update_mode in (4,5))
  10368.     begin
  10369.         declare @tranid sysname
  10370.  
  10371.         begin tran
  10372.         --
  10373.         -- process MSreplication_queue
  10374.         --
  10375.         select @retcode = 0
  10376.         if (exists (select * from sysobjects 
  10377.             where name = 'MSreplication_queue'))
  10378.         begin
  10379.             --
  10380.             -- Strictly speaking we do no need
  10381.             -- to delete but, makes it easy for
  10382.             -- the queue reader agent
  10383.             -- Do not delete any reset messages
  10384.             --
  10385.             delete dbo.MSreplication_queue
  10386.                 where publisher = UPPER(@publisher)
  10387.                 and publisher_db =  @publisher_db
  10388.                 and publication = @publication
  10389.                 and tranid not like N'sub-reset%'
  10390.         end
  10391.         else
  10392.         begin
  10393.             --
  10394.             -- first queue subscription is being initialized
  10395.             -- create queue if necessary
  10396.             --
  10397.             exec @retcode = sp_MScreate_sub_tables
  10398.                 @tran_sub_table = 0,
  10399.                 @property_table = 0,
  10400.                 @sqlqueue_table = 1
  10401.         end
  10402.         if (@retcode != 0 or @@error != 0)
  10403.         begin
  10404.             if (@@trancount > 0)
  10405.                 rollback tran
  10406.             return (1)    
  10407.         end
  10408.         --
  10409.         -- process MSrepl_queuedtraninfo
  10410.         --
  10411.         if (exists (select * from sysobjects 
  10412.             where name = 'MSrepl_queuedtraninfo'))
  10413.         begin
  10414.             --
  10415.             -- Strictly speaking we do no need
  10416.             -- to delete but, makes it easy for
  10417.             -- the queue reader agent
  10418.             -- Do not delete any reset messages
  10419.             --
  10420.             delete dbo.MSrepl_queuedtraninfo
  10421.                 where publisher = UPPER(@publisher)
  10422.                 and publisher_db =  @publisher_db
  10423.                 and publication = @publication
  10424.                 and tranid not like N'sub-reset%'
  10425.         end
  10426.         else
  10427.         begin
  10428.             --
  10429.             -- first queue subscription is being initialized
  10430.             -- create the traninfo if necessary
  10431.             --
  10432.             exec @retcode = sp_MScreate_sub_tables
  10433.                 @tran_sub_table = 0,
  10434.                 @property_table = 0,
  10435.                 @sqlqueue_table = 1
  10436.         end
  10437.         if (@retcode != 0 or @@error != 0)
  10438.         begin
  10439.             if (@@trancount > 0)
  10440.                 rollback tran
  10441.             return (1)    
  10442.         end
  10443.         --
  10444.         -- for subscription reinitialization we
  10445.         -- need to insert a RESYNC command message
  10446.         --
  10447.         select @vbartid = cast(@artid as varbinary(20))
  10448.                 ,@tranid = N'sub-reset-' + cast(NEWID() as sysname)
  10449.         insert into dbo.MSreplication_queue (publisher, publisher_db,
  10450.             publication,tranid, commandtype, data, datalen)
  10451.         values (UPPER(@publisher), @publisher_db, 
  10452.             @publication, @tranid, 2, @vbartid, datalength(@vbartid))
  10453.         if ((@@error != 0) or (@retcode != 0))
  10454.         begin
  10455.             if (@@trancount > 0)
  10456.                 rollback tran
  10457.             return (1)    
  10458.         end
  10459.         --
  10460.         -- add an entry in MSrepl_queuedtraninfo
  10461.         --
  10462.         insert into dbo.MSrepl_queuedtraninfo (publisher,publisher_db,publication,tranid,maxorderkey,commandcount)
  10463.         values (UPPER(@publisher),@publisher_db,@publication,@tranid,@@identity,1)
  10464.     end
  10465.  
  10466.     commit tran
  10467.     return 0
  10468. end            
  10469. GO
  10470. exec dbo.sp_MS_marksystemobject sp_MSreset_queue
  10471. go
  10472. grant execute on dbo.sp_MSreset_queue to public
  10473. go
  10474.  
  10475. --------------------------------------------------------------------------------
  10476. --. sp_MScreate_sub_tables
  10477. --------------------------------------------------------------------------------
  10478.  
  10479. if exists (select * from sysobjects
  10480.     where type = 'P' and name = 'sp_MScreate_sub_tables')
  10481. drop procedure sp_MScreate_sub_tables
  10482. go
  10483.  
  10484. raiserror('Creating procedure sp_MScreate_sub_tables', 0,1)
  10485. GO
  10486. CREATE PROCEDURE sp_MScreate_sub_tables 
  10487. (
  10488. @tran_sub_table bit = 0,
  10489. @property_table bit = 1,
  10490. @sqlqueue_table bit = 0
  10491. )
  10492. as
  10493. BEGIN
  10494.     set nocount on
  10495.     declare @retcode int
  10496.  
  10497.     IF @tran_sub_table = 1 and
  10498.         (NOT EXISTS (SELECT * FROM sysobjects WHERE 
  10499.         type = 'U' AND name = 'MSreplication_subscriptions')) 
  10500.     BEGIN
  10501.         CREATE TABLE dbo.MSreplication_subscriptions
  10502.         (
  10503.         publisher sysname NOT NULL,
  10504.         publisher_db sysname NOT NULL, 
  10505.         publication sysname NULL, 
  10506.         independent_agent bit NOT NULL,
  10507.         subscription_type int NOT NULL,
  10508.         distribution_agent sysname NULL, 
  10509.         time smalldatetime NOT NULL,
  10510.         description nvarchar(255) NULL,
  10511.         transaction_timestamp varbinary(16) NOT NULL,
  10512.         -- SyncTran
  10513.         update_mode tinyint NOT NULL,
  10514.         agent_id binary(16) NULL,
  10515.         subscription_guid binary(16) NULL,
  10516.         subid binary(16) NULL,
  10517.         immediate_sync bit NOT NULL default 1 -- sync_mode with a default of 1
  10518.         )
  10519.         IF @@ERROR <> 0
  10520.             GOTO UNDO
  10521.         CREATE UNIQUE CLUSTERED INDEX uc1MSReplication_subscriptions ON
  10522.                 MSreplication_subscriptions(publication, publisher_db, publisher, subscription_type)
  10523.         IF @@ERROR <> 0
  10524.             GOTO UNDO
  10525.  
  10526.         EXEC dbo.sp_MS_marksystemobject 'MSreplication_subscriptions'
  10527.          IF @@ERROR <> 0
  10528.             GOTO UNDO
  10529.     END    
  10530.  
  10531.  
  10532.     IF @tran_sub_table = 1
  10533.     BEGIN
  10534.         IF NOT EXISTS (SELECT * FROM sysobjects WHERE 
  10535.             type = 'U' AND name = 'MSsubscription_agents') 
  10536.         BEGIN
  10537.             CREATE TABLE dbo.MSsubscription_agents
  10538.             (
  10539.             id int identity,
  10540.             publisher sysname NOT NULL,
  10541.             publisher_db sysname NOT NULL, 
  10542.             publication sysname NOT NULL, 
  10543.             subscription_type int NOT NULL,
  10544.             queue_id sysname NULL,
  10545.             update_mode tinyint default 0 not null, -- 0 = read only, 1 = sync/immediate, 2 = queued, 3 = failover, 4 = sqlqueued, 5 = sqlqueued failover
  10546.             failover_mode bit default 0 not null, -- 0 - sync/immediate, 1 = queued
  10547.             spid int NOT NULL,
  10548.             login_time datetime NOT NULL,
  10549.             allow_subscription_copy bit default 0 not null,
  10550.             attach_state int default 0 not null,    -- 0: not attached 1 attached but not processed 2 attached and processed.
  10551.             attach_version binary(16) default newid() not null,
  10552.             last_sync_status int NULL, -- allow null for upgrade
  10553.             last_sync_summary sysname NULL, -- allow null for upgrade
  10554.             last_sync_time datetime NULL, -- allow null for upgrade
  10555.             queue_server sysname NULL -- only used for MSMQ based updating subscribers
  10556.             )
  10557.             IF @@ERROR <> 0
  10558.                 GOTO UNDO
  10559.  
  10560.             CREATE unique CLUSTERED INDEX ucMSsubscription_agents ON dbo.MSsubscription_agents
  10561.                 (publication, publisher_db, publisher, subscription_type)
  10562.  
  10563.             CREATE INDEX ucMSsubscription_agents_id ON dbo.MSsubscription_agents
  10564.                 (id)
  10565.  
  10566.             EXEC dbo.sp_MS_marksystemobject 'MSsubscription_agents'
  10567.             IF @@ERROR <> 0
  10568.                 GOTO UNDO
  10569.  
  10570.             grant select on dbo.MSsubscription_agents to public
  10571.             IF @@ERROR <> 0
  10572.                 GOTO UNDO
  10573.         END
  10574.         ELSE
  10575.         BEGIN
  10576.             --
  10577.             -- table exists - add new columns
  10578.             --
  10579.             if not exists (select * from dbo.syscolumns where 
  10580.                 id = object_id('MSsubscription_agents') and
  10581.                 name = 'queue_server')
  10582.             begin
  10583.                 alter table dbo.MSsubscription_agents add queue_server sysname NULL
  10584.                 exec dbo.sp_MSupdate_mqserver_subdb
  10585.             end
  10586.         END
  10587.      END
  10588.  
  10589.     IF @property_table = 1 and
  10590.         NOT EXISTS (SELECT * FROM sysobjects WHERE 
  10591.         type = 'U' AND
  10592.         name = 'MSsubscription_properties')
  10593.     BEGIN
  10594.         BEGIN TRAN
  10595.  
  10596.         CREATE TABLE dbo.MSsubscription_properties
  10597.         (
  10598.         publisher                        sysname        NOT NULL,
  10599.         publisher_db                    sysname        NOT NULL,
  10600.         publication                        sysname        NOT NULL,
  10601.         publication_type                int            NOT NULL,
  10602.         publisher_login                    sysname        NULL,
  10603.         publisher_password                nvarchar(524) NULL,
  10604.         publisher_security_mode            int            NOT NULL,
  10605.         distributor                        sysname        NULL,
  10606.         distributor_login                sysname        NULL,
  10607.         distributor_password            nvarchar(524) NULL,
  10608.         distributor_security_mode        int            NOT NULL,
  10609.         ftp_address                        sysname        NULL,
  10610.         ftp_port                        int            NULL,
  10611.         ftp_login                        sysname        NULL,
  10612.         ftp_password                    nvarchar(524) NULL,
  10613.         alt_snapshot_folder             nvarchar(255) NULL,
  10614.         working_directory               nvarchar(255) NULL,
  10615.         use_ftp                            bit default 0 NOT NULL,
  10616.         dts_package_name                sysname NULL,
  10617.         dts_package_password            nvarchar(524) NULL,
  10618.         -- default to be at the subscriber
  10619.         dts_package_location            int    default 1 NOT NULL,
  10620.         enabled_for_syncmgr                bit default 0 NOT NULL,
  10621.         offload_agent                   bit default 0 NOT NULL,
  10622.         offload_server                  sysname     NULL,
  10623.         dynamic_snapshot_location       nvarchar(255) NULL
  10624.         )
  10625.         IF @@ERROR <> 0
  10626.             GOTO UNDO
  10627.  
  10628.         CREATE UNIQUE CLUSTERED INDEX uc1MSsubscription_properties ON
  10629.                 MSsubscription_properties(publication, publisher_db, publisher)
  10630.         IF @@ERROR <> 0
  10631.             GOTO UNDO
  10632.         
  10633.         EXEC @retcode = dbo.sp_MS_marksystemobject 'MSsubscription_properties'
  10634.         if @retcode <> 0 or @@error <> 0
  10635.             GOTO UNDO
  10636.  
  10637.         COMMIT TRAN
  10638.     END
  10639.  
  10640.     IF @sqlqueue_table = 1
  10641.     BEGIN
  10642.         declare @folddata bit
  10643.  
  10644.         BEGIN TRAN    
  10645.         if EXISTS (SELECT * FROM dbo.sysobjects WHERE 
  10646.                 type = 'U' AND name = 'MSreplication_queue')
  10647.         BEGIN
  10648.             --
  10649.             -- table exists - check if we need to add columns
  10650.             --
  10651.             if not exists (select * from dbo.syscolumns where 
  10652.                     id = object_id('MSreplication_queue') and
  10653.                     name = 'cmdstate')
  10654.             BEGIN
  10655.                 ALTER TABLE dbo.MSreplication_queue ADD cmdstate bit DEFAULT 0 NOT NULL
  10656.                 IF @@ERROR <> 0
  10657.                     GOTO UNDO
  10658.             END    
  10659.  
  10660.             --
  10661.             -- change data column from text to varbinary(8000)
  10662.             -- SPECIAL CASE : since a simple ALTER does not work here
  10663.             -- we create a temp table to save the existing data and then
  10664.             -- recreate the table
  10665.             --
  10666.             if exists (select * from dbo.syscolumns 
  10667.                 where id = object_id('MSreplication_queue') and
  10668.                 name = 'data' and xtype = 34)
  10669.             begin
  10670.                 --
  10671.                 -- save existing column data
  10672.                 --
  10673.                 if exists (select * from dbo.MSreplication_queue)
  10674.                 begin
  10675.                     select @folddata = 1
  10676.                     create table #olddata (
  10677.                         publisher                    sysname collate database_default not null ,
  10678.                         publisher_db                sysname collate database_default not null ,
  10679.                         publication                    sysname collate database_default not null ,
  10680.                         tranid                        sysname collate database_default not null ,
  10681.                         data                        varbinary(8000) NULL ,
  10682.                         datalen                     int,
  10683.                         commandtype                    int,
  10684.                         insertdate                    datetime ,
  10685.                         orderkey                    bigint,
  10686.                         cmdstate                    bit)
  10687.                         
  10688.                     insert into #olddata 
  10689.                         select publisher, publisher_db, publication, tranid, CAST(data as varbinary(8000)), 
  10690.                                 datalen, commandtype, insertdate, orderkey, cmdstate 
  10691.                         from dbo.MSreplication_queue
  10692.                     if @@error != 0
  10693.                         goto UNDO
  10694.                 end
  10695.  
  10696.                 --
  10697.                 -- drop table
  10698.                 --
  10699.                 DROP TABLE dbo.MSreplication_queue
  10700.                 IF @@ERROR <> 0
  10701.                     GOTO UNDO                
  10702.             end        
  10703.         END
  10704.  
  10705.         --
  10706.         -- Create table if it does not exist
  10707.         --
  10708.         if NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE 
  10709.                 type = 'U' AND name = 'MSreplication_queue')        
  10710.         BEGIN        
  10711.             CREATE TABLE dbo.MSreplication_queue (
  10712.                 publisher                     sysname NOT NULL ,
  10713.                 publisher_db                 sysname NOT NULL ,
  10714.                 publication                 sysname NOT NULL ,
  10715.                 tranid                         sysname NOT NULL ,
  10716.                 data                         varbinary(8000) NULL ,
  10717.                 datalen                     int DEFAULT 0 ,
  10718.                 commandtype                 int NULL ,
  10719.                 insertdate                     datetime DEFAULT GETDATE(),
  10720.                 orderkey                    bigint IDENTITY(1,1) PRIMARY KEY,
  10721.                 cmdstate                    bit DEFAULT 0 NOT NULL
  10722.             )
  10723.             IF @@ERROR <> 0
  10724.                 GOTO UNDO
  10725.  
  10726.             /****
  10727.             CREATE NONCLUSTERED INDEX nc1MSreplication_queue ON
  10728.                     MSreplication_queue(tranid)
  10729.             IF @@ERROR <> 0
  10730.                 GOTO UNDO
  10731.             ****/
  10732.  
  10733.             EXEC @retcode = dbo.sp_MS_marksystemobject 'MSreplication_queue'
  10734.             if @retcode <> 0 or @@error <> 0
  10735.                 GOTO UNDO
  10736.  
  10737.             --
  10738.             -- Do we need to restore old data
  10739.             --
  10740.             if (@folddata = 1)
  10741.             begin
  10742.                 insert dbo.MSreplication_queue (publisher, publisher_db, publication, tranid, data,
  10743.                             datalen, commandtype, insertdate, cmdstate)
  10744.                     select publisher, publisher_db, publication, tranid, data, 
  10745.                                 datalen, commandtype, insertdate, cmdstate 
  10746.                         from #olddata
  10747.                         order by orderkey
  10748.                 if @@error != 0
  10749.                     goto UNDO
  10750.                 
  10751.                 drop table #olddata
  10752.                 if @@error != 0
  10753.                     goto UNDO
  10754.             end
  10755.         END
  10756.         --
  10757.         -- Table MSrepl_queuedtraninfo
  10758.         -- Create table if it does not exist
  10759.         --
  10760.         if NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE 
  10761.                 type = 'U' AND name = 'MSrepl_queuedtraninfo')
  10762.         BEGIN
  10763.             CREATE TABLE dbo.MSrepl_queuedtraninfo (
  10764.                 publisher                     sysname NOT NULL ,
  10765.                 publisher_db                     sysname NOT NULL ,
  10766.                 publication                     sysname NOT NULL ,
  10767.                 tranid                         sysname NOT NULL ,
  10768.                 maxorderkey                    bigint NOT NULL,
  10769.                 commandcount                bigint NOT NULL
  10770.             )
  10771.             IF @@ERROR <> 0
  10772.                 GOTO UNDO
  10773.             CREATE CLUSTERED INDEX c1MSrepl_queuedtraninfo ON
  10774.                     MSrepl_queuedtraninfo(publisher,publisher_db,publication,tranid)
  10775.             IF @@ERROR <> 0
  10776.                 GOTO UNDO
  10777.             EXEC @retcode = dbo.sp_MS_marksystemobject 'MSrepl_queuedtraninfo'
  10778.             if @retcode <> 0 or @@error <> 0
  10779.                 GOTO UNDO
  10780.             --
  10781.             -- Populate this table as necessary
  10782.             --
  10783.             exec @retcode = dbo.sp_populateqtraninfo
  10784.             if @retcode <> 0 or @@error <> 0
  10785.                 GOTO UNDO
  10786.         END
  10787.         COMMIT TRAN
  10788.     END
  10789.  
  10790.     return(0)
  10791.     
  10792. UNDO:
  10793.     IF @@TRANCOUNT = 1
  10794.         ROLLBACK TRAN
  10795.     ELSE
  10796.         COMMIT TRAN  
  10797.     return(1) 
  10798. END
  10799. go
  10800. exec dbo.sp_MS_marksystemobject sp_MScreate_sub_tables
  10801. go
  10802. grant exec on dbo.sp_MScreate_sub_tables to public
  10803. go
  10804.  
  10805. --------------------------------------------------------------------------------
  10806. --. sp_MSsendtosqlqueue
  10807. --------------------------------------------------------------------------------
  10808.  
  10809. if exists (select * from sysobjects
  10810.     where type = 'P' and name = 'sp_MSsendtosqlqueue')
  10811. drop procedure sp_MSsendtosqlqueue
  10812. go
  10813. raiserror(15339,-1,-1,'sp_MSsendtosqlqueue')
  10814. GO
  10815. create proc sp_MSsendtosqlqueue (
  10816.     @objid int
  10817.     ,@publisher sysname
  10818.     ,@publisher_db sysname
  10819.     ,@publication sysname
  10820.     ,@owner sysname
  10821.     ,@tranid sysname
  10822.     ,@data varbinary(8000)
  10823.     ,@datalen int
  10824.     ,@commandtype int = 1
  10825.     ,@cmdstate bit = 0
  10826. )
  10827. as
  10828. begin
  10829.     set nocount on
  10830.     --
  10831.     -- Security check
  10832.     -- Make sure this proc is infact being called from the given object(trigger)
  10833.     -- 
  10834.     if (trigger_nestlevel(@objid) = 0)
  10835.     begin
  10836.         raiserror(14126, 16, 2)
  10837.         return 1
  10838.     end
  10839.     --
  10840.     -- Security check: the caller of this SP has to be one of the 
  10841.     -- predefined replication objects for this subscription
  10842.     --
  10843.     if (@objid not in (select object_id(quotename(@owner) + N'.' + quotename([object_name])) 
  10844.         from dbo.MSreplication_objects
  10845.         where publisher = @publisher and publisher_db = @publisher_db and
  10846.                 publication = @publication and object_type = 'T'))
  10847.     begin
  10848.         raiserror(14126, 16, 3)
  10849.         return 1
  10850.     end
  10851.     --
  10852.     -- insert into the queue table
  10853.     --
  10854.     insert into dbo.MSreplication_queue (publisher,publisher_db,publication,tranid,data,datalen,commandtype,cmdstate)
  10855.         values(UPPER(@publisher),@publisher_db,@publication,@tranid,@data,@datalen,@commandtype,@cmdstate)
  10856.     if (@@error != 0)
  10857.         return 1
  10858.     --
  10859.     -- Update MSrepl_queuedtraninfo
  10860.     --
  10861.     if exists (select *
  10862.         from dbo.MSrepl_queuedtraninfo
  10863.         where publisher = UPPER(@publisher) 
  10864.             and publisher_db = @publisher_db 
  10865.             and publication = @publication
  10866.             and tranid = @tranid)
  10867.     begin
  10868.         --
  10869.         -- row for this transaction exists - update it
  10870.         --
  10871.         update dbo.MSrepl_queuedtraninfo
  10872.         set maxorderkey = @@identity
  10873.             ,commandcount = commandcount + 1
  10874.         where publisher = UPPER(@publisher)
  10875.             and publisher_db = @publisher_db 
  10876.             and publication = @publication
  10877.             and tranid = @tranid
  10878.     end
  10879.     else
  10880.     begin
  10881.         --
  10882.         -- row for this transaction does not exist - insert it
  10883.         --
  10884.         insert into dbo.MSrepl_queuedtraninfo (publisher,publisher_db,publication,tranid,maxorderkey,commandcount)
  10885.         values (UPPER(@publisher),@publisher_db,@publication,@tranid,@@identity,1)
  10886.     end
  10887.     if (@@error != 0)
  10888.         return 1
  10889.     --
  10890.     -- all done
  10891.     --
  10892.     return 0
  10893. end
  10894. go
  10895. exec dbo.sp_MS_marksystemobject sp_MSsendtosqlqueue
  10896. go            
  10897. grant execute on dbo.sp_MSsendtosqlqueue to public
  10898. go
  10899.  
  10900.  
  10901. --------------------------------------------------------------------------------
  10902. --. sp_populateqtraninfo
  10903. --------------------------------------------------------------------------------
  10904.  
  10905. if exists (select * from sysobjects
  10906.     where type = 'P' and name = 'sp_populateqtraninfo')
  10907. drop procedure sp_populateqtraninfo
  10908. go
  10909. raiserror('Creating procedure sp_populateqtraninfo', 0,1)
  10910. GO
  10911. CREATE PROCEDURE sp_populateqtraninfo 
  10912. as
  10913. begin
  10914.     --
  10915.     -- initiate local transaction
  10916.     --
  10917.     begin tran sp_populateqtraninfo
  10918.     save tran sp_populateqtraninfo
  10919.     --
  10920.     -- see if we need to populate
  10921.     --
  10922.     if EXISTS (SELECT * FROM dbo.MSreplication_queue)
  10923.     begin
  10924.         --
  10925.         -- There is data in queue
  10926.         -- Populate MSrepl_queuedtraninfo based on what is there
  10927.         --
  10928.         declare @publisher sysname
  10929.                 ,@publisherdb sysname
  10930.                 ,@publication sysname
  10931.                 ,@tranid sysname
  10932.                 ,@orderkey bigint
  10933.                 
  10934.         declare #htctranseq cursor local for
  10935.             select publisher, publisher_db, publication, tranid, orderkey
  10936.             from dbo.MSreplication_queue with (READPAST) 
  10937.             order by orderkey asc
  10938.         open #htctranseq
  10939.         fetch #htctranseq into @publisher, @publisherdb, @publication, @tranid, @orderkey
  10940.         IF @@ERROR <> 0
  10941.             goto cleanup
  10942.         while (@@fetch_status != -1)
  10943.         begin
  10944.             --
  10945.             -- update/insert entry in MSrepl_queuedtraninfo for this transaction
  10946.             --
  10947.             if exists (    select *
  10948.                 from dbo.MSrepl_queuedtraninfo
  10949.                 where publisher = UPPER(@publisher) 
  10950.                     and publisher_db = @publisherdb 
  10951.                     and publication = @publication
  10952.                     and tranid = @tranid)
  10953.             begin
  10954.                 --
  10955.                 -- row for this transaction exists - update it
  10956.                 --
  10957.                 update dbo.MSrepl_queuedtraninfo
  10958.                 set maxorderkey = @orderkey
  10959.                     ,commandcount = commandcount + 1
  10960.                 where publisher = UPPER(@publisher) 
  10961.                     and publisher_db = @publisherdb 
  10962.                     and publication = @publication
  10963.                     and tranid = @tranid
  10964.             end
  10965.             else
  10966.             begin
  10967.                 --
  10968.                 -- row for this transaction does not exist - insert it
  10969.                 --
  10970.                 insert into dbo.MSrepl_queuedtraninfo (publisher,publisher_db,publication,tranid,maxorderkey,commandcount)
  10971.                 values (UPPER(@publisher),@publisherdb,@publication,@tranid,@orderkey,1)
  10972.             end
  10973.             IF @@ERROR <> 0
  10974.                 goto cleanup
  10975.             --
  10976.             -- get the next row
  10977.             --
  10978.             fetch #htctranseq into @publisher, @publisherdb, @publication, @tranid, @orderkey
  10979.         end
  10980.         close #htctranseq
  10981.         deallocate #htctranseq
  10982.     end
  10983.     --
  10984.     -- commit local transaction
  10985.     --
  10986.     commit tran sp_populateqtraninfo
  10987.     --
  10988.     -- all done
  10989.     --
  10990.     return 0
  10991.  
  10992. cleanup:
  10993.     --
  10994.     -- error cleanup
  10995.     -- rollback local tran
  10996.     --
  10997.     rollback tran sp_populateqtraninfo
  10998.     commit tran
  10999.     return 1
  11000. end
  11001. go
  11002. exec dbo.sp_MS_marksystemobject sp_populateqtraninfo
  11003. go
  11004.  
  11005. --------------------------------------------------------------------------------
  11006. --. sp_vupgrade_subscription_tables
  11007. --------------------------------------------------------------------------------
  11008.  
  11009. if exists (select * from sysobjects
  11010.     where type = 'P' and name = 'sp_vupgrade_subscription_tables')
  11011. drop procedure sp_vupgrade_subscription_tables
  11012. go
  11013. raiserror('Creating procedure sp_vupgrade_subscription_tables', 0,1)
  11014. GO
  11015. create procedure sp_vupgrade_subscription_tables
  11016. as
  11017. begin
  11018. /* 
  11019.  * Process schema and metadata changes common to transactional pub/sub databases. Exception is creation
  11020.  * of MSrepl_identity_range table needed for tran and merge publishing databases and merge subscr db's.
  11021.  *
  11022.  * Setup version upgrade procedure call order:
  11023.  *    sp_vupgrade_replication -> sp_vupgrade_subscription_databases -> sp_vupgrade_subscription_tables
  11024. */
  11025.  
  11026.     -- raiserror('sp_vupgrade_subscription_tables', 0,1) with nowait
  11027.  
  11028.     set nocount on 
  11029.  
  11030.     DECLARE @table_name sysname
  11031.     declare @retcode int
  11032.  
  11033.     -- Identity range management; create in  publishing databases
  11034.     if exists (select * from sysobjects where name = 'sysarticles')
  11035.     begin
  11036.         if not exists (select * from sysobjects where name = 'MSpub_identity_range')
  11037.         begin        
  11038.             CREATE TABLE dbo.MSpub_identity_range
  11039.             (
  11040.                 objid int not null,
  11041.                 range bigint not null,
  11042.                 pub_range bigint not null,
  11043.                 current_pub_range bigint not null,
  11044.                 threshold int not null,
  11045.                 last_seed bigint null -- It will be not when uninitialized.
  11046.             )     
  11047.  
  11048.             IF @@ERROR <> 0
  11049.             BEGIN
  11050.                 return(1)
  11051.             END
  11052.  
  11053.             -- mark the index as a system object
  11054.             exec dbo.sp_MS_marksystemobject 'MSpub_identity_range'
  11055.  
  11056.             IF @@ERROR <> 0
  11057.             BEGIN
  11058.                 return(1)
  11059.             END
  11060.  
  11061.             create unique nonclustered index unc1MSpub_identity_range
  11062.                 on MSpub_identity_range (objid)
  11063.  
  11064.             IF @@ERROR <> 0
  11065.             BEGIN
  11066.                 return(1)
  11067.             END
  11068.         end
  11069.     end
  11070.  
  11071.     -- Identity range management; create in all publishing databases and merge subscription databases (Shiloh)
  11072.     if exists (select * from sysobjects where name = 'sysmergearticles')
  11073.     begin
  11074.         if not exists (select * from sysobjects where name = 'MSrepl_identity_range')
  11075.         begin        
  11076.             create table dbo.MSrepl_identity_range (
  11077.                 objid                    int not NULL primary key,
  11078.                 next_seed                bigint NULL, --resource control
  11079.                 pub_range                bigint NULL, --publisher range
  11080.                 range                    bigint NULL, -- set by sp_addmergearticle
  11081.                 max_identity            bigint NULL, --resource control
  11082.                 threshold                int    NULL,    --in percentage, set by sp_addmergearticle
  11083.                 current_max                bigint NULL    --max value for current check constraint,set by sp_addmergearticle
  11084.                 )
  11085.             exec dbo.sp_MS_marksystemobject MSrepl_identity_range
  11086.             if @@ERROR <> 0
  11087.                 return(1)
  11088.             grant select on MSrepl_identity_range to public
  11089.         end
  11090.     end
  11091.  
  11092.     --    Create unique index on tables that did not have one previously. The index is not created
  11093.     --    if duplicates rows exist in the table. 
  11094.  
  11095.     --    MSreplication_subscriptions (SQL7.0 SP1)
  11096.     SELECT @table_name = N'MSreplication_subscriptions'
  11097.     IF EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSreplication_subscriptions' ) or 
  11098.         EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSsubscription_agents' )
  11099.     BEGIN
  11100.         IF EXISTS ( SELECT publication, publisher_db, publisher, subscription_type 
  11101.             FROM MSreplication_subscriptions
  11102.             GROUP BY publication, publisher_db, publisher, subscription_type
  11103.             HAVING COUNT(*) > 1 )
  11104.             RAISERROR (21203, 10, 1, @table_name)
  11105.         ELSE
  11106.             IF NOT EXISTS ( SELECT * FROM sysindexes WHERE name = 'uc1MSReplication_subscriptions' AND
  11107.                 id = OBJECT_ID('MSreplication_subscriptions') )
  11108.                 CREATE UNIQUE CLUSTERED INDEX uc1MSReplication_subscriptions ON
  11109.                 MSreplication_subscriptions(publication, publisher_db, publisher, subscription_type)
  11110.         
  11111.         -- Create MSsubscription_agents table 
  11112.         exec @retcode = dbo.sp_MScreate_sub_tables
  11113.             @tran_sub_table = 1,
  11114.             @property_table = 0,
  11115.             @sqlqueue_table = 0
  11116.         IF @@ERROR <> 0 or @retcode <> 0
  11117.             RETURN(1)
  11118.  
  11119.         -- Add new columns to MSsubscription_agents, for 8.0 pre beta upgrade.
  11120.  
  11121.         -- status of the last sync (Shiloh)
  11122.         if not exists (select * from syscolumns where id = object_id('MSsubscription_agents') and
  11123.                             name = 'last_sync_status')
  11124.         begin
  11125.                 alter table MSsubscription_agents add last_sync_status int NULL
  11126.                 if @@ERROR <> 0
  11127.                     return 1
  11128.         end
  11129.  
  11130.         -- summary message of the last sync (Shiloh)
  11131.         if not exists (select * from syscolumns where id = object_id('MSsubscription_agents') and
  11132.                             name = 'last_sync_summary')
  11133.         begin
  11134.                 alter table MSsubscription_agents add last_sync_summary sysname NULL
  11135.                 if @@ERROR <> 0
  11136.                     return 1
  11137.         end
  11138.  
  11139.         -- summary message of the last sync (Shiloh)
  11140.         if not exists (select * from syscolumns where id = object_id('MSsubscription_agents') and
  11141.                             name = 'last_sync_time')
  11142.         begin
  11143.                 alter table MSsubscription_agents add last_sync_time datetime NULL
  11144.                 if @@ERROR <> 0
  11145.                     return 1
  11146.         end
  11147.     END
  11148.  
  11149.     --    MSreplication_objects (SQL7.0 SP1)
  11150.     SELECT @table_name = N'MSreplication_objects'
  11151.     IF EXISTS ( SELECT * FROM sysobjects WHERE name = 'MSreplication_objects' ) 
  11152.     BEGIN
  11153.         IF EXISTS ( SELECT object_name
  11154.             FROM MSreplication_objects
  11155.             GROUP BY object_name
  11156.             HAVING COUNT(*) > 1 )
  11157.             RAISERROR (21203, 10, 3, @table_name)
  11158.         ELSE    
  11159.             IF NOT EXISTS ( SELECT * FROM sysindexes WHERE name = 'ucMSreplication_objects' AND
  11160.                 id = OBJECT_ID('MSreplication_objects') )
  11161.                 CREATE UNIQUE CLUSTERED INDEX ucMSreplication_objects ON dbo.MSreplication_objects(object_name)
  11162.     END
  11163.  
  11164.     --    MSreplication_queue (SQL2000 SP3)
  11165.     SELECT @table_name = N'MSreplication_queue'
  11166.     IF EXISTS ( SELECT * FROM sysobjects WHERE name = @table_name ) 
  11167.     BEGIN
  11168.         exec @retcode = sp_MScreate_sub_tables
  11169.             @tran_sub_table = 0,
  11170.             @property_table = 0,
  11171.             @sqlqueue_table = 1
  11172.         IF @@ERROR <> 0 or @retcode <> 0
  11173.             RETURN(1)
  11174.     END
  11175.  
  11176.     --    MSrepl_queuedtraninfo (SQL2000 SP3)
  11177.     SELECT @table_name = N'MSrepl_queuedtraninfo'
  11178.     IF EXISTS ( SELECT * FROM sysobjects WHERE name = @table_name ) 
  11179.     BEGIN
  11180.         exec @retcode = sp_MScreate_sub_tables
  11181.             @tran_sub_table = 0,
  11182.             @property_table = 0,
  11183.             @sqlqueue_table = 1
  11184.         IF @@ERROR <> 0 or @retcode <> 0
  11185.             RETURN(1)
  11186.     END
  11187.  
  11188. end
  11189. go
  11190. exec dbo.sp_MS_marksystemobject sp_vupgrade_subscription_tables
  11191. go
  11192.  
  11193. dump tran master with no_log
  11194. go
  11195. sp_configure 'allow updates',0
  11196. go
  11197. reconfigure with override
  11198. go
  11199. checkpoint
  11200. go
  11201.  
  11202. --
  11203. -- Now we will upgrade the subscriber databases to ensure
  11204. -- that the new tables needed for queued replication are in place
  11205. --
  11206. set nocount on
  11207. declare @dbname nvarchar(270), @has_dbaccess bit
  11208.  
  11209. declare current_db CURSOR LOCAL FAST_FORWARD for 
  11210.     select N'[' + replace(name, N']', N']]') + N']', has_dbaccess(name) from master..sysdatabases 
  11211.         WHERE name <> N'master' collate database_default
  11212.         AND name <> N'tempdb' collate database_default
  11213.         AND name <> N'msdb' collate database_default
  11214.     for read only
  11215.  
  11216. -- Note: dbname is quoted!
  11217. open current_db
  11218. fetch current_db into @dbname, @has_dbaccess
  11219. while ( @@fetch_status <> -1 )
  11220. begin
  11221.  
  11222.     -- upgrade repl tables in sub dbs if needed - sub dbs are not marked with subscribed status 
  11223.     -- skip any database in an offline state and write warning to upgrade log
  11224.     if ( @has_dbaccess = 1 )
  11225.     begin
  11226.         raiserror( 21377, 0, 1, @dbname) with nowait
  11227.         exec ('use '+ @dbname + ' exec dbo.sp_vupgrade_subscription_tables')
  11228.     end
  11229.     else
  11230.     begin
  11231.         raiserror( 21373, 10, 1, @dbname) with nowait
  11232.     end
  11233.  
  11234.     fetch next from current_db into @dbname, @has_dbaccess
  11235. end
  11236. close current_db
  11237. deallocate current_db
  11238. --
  11239. -- all done
  11240. --
  11241. go
  11242.  
  11243.  
  11244. set ANSI_NULLS off
  11245. go
  11246. use master
  11247. go
  11248. dump tran master with no_log
  11249. go
  11250. checkpoint
  11251. go
  11252. --------------------------------------------------------------------------------
  11253. --. sp_MSmakectsview
  11254. --------------------------------------------------------------------------------
  11255. if exists (select * from sysobjects
  11256.     where type = 'P' and name = 'sp_MSmakectsview')
  11257. drop procedure sp_MSmakectsview
  11258. go
  11259. raiserror('Creating procedure sp_MSmakectsview', 0,1)
  11260. GO
  11261.  
  11262. create procedure sp_MSmakectsview
  11263.     @publication sysname,
  11264.     @ctsview     sysname,
  11265.     @dynamic_snapshot_views_table_name sysname = null
  11266. AS
  11267.     set nocount on
  11268.     declare @pubid          uniqueidentifier
  11269.     declare @artid          uniqueidentifier
  11270.     declare @pubidstr        nvarchar(40)
  11271.     declare @artidstr        nvarchar(40)
  11272.     declare @objid        int
  11273.     declare @tablenick    int
  11274.     declare @new_inactive int
  11275.     declare @new_active int
  11276.     declare @tablenickstr nvarchar(12)
  11277.     declare @command_piece nvarchar(2000)
  11278.     declare @rowguidcolname nvarchar(140)
  11279.     declare @view_type    int
  11280.     declare    @view_name  nvarchar(270)
  11281.     declare @or_after_first nvarchar(100)
  11282.     declare @select_command nvarchar(4000)
  11283.     declare @retcode int 
  11284.     declare @generate_per_article bit 
  11285.     declare @newidstr       nvarchar(40)
  11286.     declare @newid          uniqueidentifier
  11287.  
  11288.     /*
  11289.     **  Security Check
  11290.     */
  11291.     exec @retcode = sp_MSreplcheck_publish
  11292.     if @retcode <> 0 or @@error <> 0
  11293.         return 1
  11294.  
  11295.     /* By default the @generate_per_article is OFF */
  11296.     set @generate_per_article = 0
  11297.  
  11298.     set @new_inactive = 5 /* value of SQLDMOArtStat_New_Inactive */
  11299.     set @new_active = 6 /* value of SQLDMOArtStat_New_Active */
  11300.  
  11301.     if @ctsview IS NULL
  11302.         set @generate_per_article = 1
  11303.     
  11304.     select @retcode = 0
  11305.     set @or_after_first = ''
  11306.  
  11307.     select @pubid = pubid from sysmergepublications where name = @publication 
  11308.         and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name()
  11309.     if @pubid is null
  11310.     BEGIN
  11311.         RAISERROR (20026, 16, -1, @publication)
  11312.         RETURN (1)
  11313.     END
  11314.  
  11315.     select @newid = newid()
  11316.     exec @retcode = dbo.sp_MSguidtostr @newid, @newidstr out
  11317.     if @@ERROR <>0 OR @retcode <> 0
  11318.         return (1)
  11319.     exec @retcode = dbo.sp_MSguidtostr @pubid, @pubidstr out
  11320.     if @@ERROR <>0 OR @retcode <> 0 
  11321.         return (1)
  11322.  
  11323.     -- create the temp tables here since the views are commong to both
  11324.     -- filtered and unfiltered per article contents views
  11325.     /* create temp table to insert into and select commands out of */
  11326.     if @generate_per_article = 1
  11327.     begin
  11328.         /* create temp table to insert into and select commands out of */
  11329.         declare @temp_cts_views table
  11330.         (
  11331.             step int identity NOT NULL,
  11332.             ctsvw sysname collate database_default null, 
  11333.             tablenickname int
  11334.         )
  11335.         if @@ERROR <> 0
  11336.             return (1)
  11337.             
  11338.         select @tablenick = min(nickname) from dbo.sysmergearticles where pubid = @pubid and status<>@new_active and status<>@new_inactive
  11339.         while @tablenick is not null
  11340.         begin
  11341.             select @artid = artid from dbo.sysmergearticles where nickname = @tablenick and pubid = @pubid
  11342.             exec @retcode = dbo.sp_MSguidtostr @artid, @artidstr out
  11343.             if @@ERROR <>0 OR @retcode <> 0 return (1)
  11344.  
  11345.             set @ctsview = 'cont_' + @newidstr + '_' + @artidstr
  11346.             if exists (select * from sysobjects where name=@ctsview and type='V')
  11347.             begin
  11348.                 declare @ownername sysname
  11349.                 declare @viewname sysname
  11350.                 
  11351.                 select @ownername = user_name(uid) from sysobjects where  name=@ctsview
  11352.                 select @viewname = QUOTENAME(@ownername) + '.' + QUOTENAME(@ctsview)
  11353.                 exec ('drop view ' + @viewname)
  11354.                 if @@ERROR<>0 return (1)
  11355.             END
  11356.  
  11357.             -- insert the view name into the temp table created in this proc
  11358.             insert into @temp_cts_views (ctsvw, tablenickname) 
  11359.                                   values(@ctsview, @tablenick)
  11360.  
  11361.             /* Advance to next article and repeat the loop */
  11362.             select @tablenick = min(nickname) from dbo.sysmergearticles where
  11363.                 pubid = @pubid and nickname > @tablenick and status<>@new_active and status<>@new_inactive
  11364.         end
  11365.     end
  11366.     else
  11367.     begin
  11368.         -- this is the regular case (called from sp_MSmakesystableviews)
  11369.         declare @tempcmd table 
  11370.         (
  11371.             phase int NOT NULL, 
  11372.             step int identity NOT NULL,
  11373.             cmdtext nvarchar(4000) collate database_default null
  11374.         )
  11375.     end
  11376.  
  11377.     /* pubidstr is needed in GUID format */
  11378.     set @pubidstr = '''' + convert(nchar(36), @pubid) + ''''
  11379.  
  11380.     
  11381.     /* Check for the no filtering cases */
  11382.     if not exists (select * from sysmergesubsetfilters where pubid = @pubid) and
  11383.        not exists (select * from sysmergearticles where pubid = @pubid and
  11384.                        len(subset_filterclause) > 0)
  11385.     begin
  11386.     -- un filtered case
  11387.         if @generate_per_article = 0
  11388.         begin
  11389.             -- If @generate_per_article = 0, an entire view is returned in @command_piece.
  11390.             set @command_piece = 'create view ' + @ctsview + ' as select * from dbo.MSmerge_contents '
  11391.  
  11392.             --5 and 6 are the new article statuses - they indicate new_inactive and new_active
  11393.             set @command_piece = @command_piece + ' where tablenick in
  11394.                 (select nickname from dbo.sysmergearticles where status<>5 and status<>6 and pubid = ' + @pubidstr + ')' 
  11395.  
  11396.             insert into @tempcmd (phase, cmdtext) values (1, @command_piece)
  11397.         end
  11398.         else
  11399.         begin
  11400.             -- per article contents view for unfiltered publication
  11401.             select @tablenick = min(nickname) from dbo.sysmergearticles where pubid = @pubid and status<>@new_active and status<>@new_inactive
  11402.             while @tablenick is not null
  11403.             begin
  11404.                 if not exists(select * from @temp_cts_views where tablenickname = @tablenick)
  11405.                     return (1)
  11406.                     
  11407.                 select @ctsview = ctsvw from @temp_cts_views where tablenickname = @tablenick
  11408.                 
  11409.                 set @tablenickstr = convert(nchar(12), @tablenick)
  11410.             
  11411.                 set @command_piece = 'create view ' + @ctsview + ' as select * from dbo.MSmerge_contents '
  11412.                 set @command_piece = @command_piece + ' where tablenick = ' + @tablenickstr
  11413.                 
  11414.                 exec @retcode= dbo.sp_executesql @command_piece
  11415.                 if @@error <> 0 or @retcode <> 0 return 1
  11416.  
  11417.                 /* Advance to next article and repeat the loop */
  11418.                 select @tablenick = min(nickname) from dbo.sysmergearticles where
  11419.                     pubid = @pubid and nickname > @tablenick and status<>@new_active and status<>@new_inactive
  11420.             end
  11421.         end        
  11422.         goto Finish
  11423.     end
  11424.  
  11425.     -- filtered case
  11426.     if @generate_per_article = 0
  11427.     begin
  11428.         set @command_piece = 'create view ' + @ctsview + ' as select * from dbo.MSmerge_contents where '
  11429.         insert into @tempcmd (phase, cmdtext) values (1, @command_piece)
  11430.     end            
  11431.  
  11432.     /* Initialize for loop over articles in this publication */
  11433.     select @tablenick = min(nickname) from dbo.sysmergearticles where pubid = @pubid and status<>@new_active and status<>@new_inactive
  11434.     while @tablenick is not null
  11435.     begin
  11436.         if @dynamic_snapshot_views_table_name is null or @dynamic_snapshot_views_table_name = N''
  11437.         begin
  11438.             select @objid = objid, @view_type = view_type, @view_name = object_name(sync_objid) from 
  11439.                 sysmergearticles where pubid = @pubid and nickname = @tablenick 
  11440.         end
  11441.         else
  11442.         begin
  11443.             select @select_command = '
  11444.                 select @objid = sma.objid, 
  11445.                        @view_type = sma.view_type, 
  11446.                        @view_name = dsvt.dynamic_snapshot_view_name 
  11447.                   from sysmergearticles sma
  11448.                 inner join ' + @dynamic_snapshot_views_table_name + ' dsvt 
  11449.                     on dsvt.artid = sma.artid            
  11450.                  where pubid = @pubid 
  11451.                    and nickname = @tablenick'
  11452.             exec sp_executesql @select_command,
  11453.                                N'@objid int output, 
  11454.                                  @view_type int output, 
  11455.                                  @view_name nvarchar(270) output,
  11456.                                  @pubid uniqueidentifier,
  11457.                                  @tablenick int',
  11458.                                @objid = @objid output,
  11459.                                @view_type = @view_type output, 
  11460.                                @view_name = @view_name output,
  11461.                                @pubid = @pubid,
  11462.                                @tablenick = @tablenick  
  11463.             if @@error<>0 return(1)
  11464.         end
  11465.         select @rowguidcolname = name from syscolumns where id = @objid and
  11466.                 columnproperty(id, name, 'isrowguidcol')=1
  11467.  
  11468.         set @rowguidcolname = QUOTENAME(@rowguidcolname)
  11469.         set @view_name = QUOTENAME(@view_name)
  11470.         set @tablenickstr = convert(nchar(12), @tablenick)
  11471.         
  11472.         -- if view_type is non-zero it means that we have a filtered article
  11473.         -- if view_type is 0 it means that we have an unfiltered article.
  11474.         -- the selects we do for the ctsview has to be different for these two cases
  11475.         if @generate_per_article = 0
  11476.         begin
  11477.             if @view_type <> 0
  11478.             begin
  11479.                 set @command_piece = @or_after_first + ' 
  11480.                 (tablenick = ' + @tablenickstr + ' and rowguid in
  11481.                     (select ' + @rowguidcolname + ' from ' + @view_name + '))'
  11482.             end
  11483.             else
  11484.             begin
  11485.                 set @command_piece = @or_after_first + ' 
  11486.                 (tablenick = ' + @tablenickstr + ')'
  11487.             end
  11488.             
  11489.             insert into @tempcmd (phase, cmdtext) values (2, @command_piece)
  11490.         end
  11491.         else
  11492.         begin
  11493.             -- by the time we reach this point we have already pregenerated the view names that should
  11494.             -- be used and stored them in the temp table @temp_cts_views
  11495.             -- check here to make sure that this article exists in the temp table
  11496.             if not exists(select * from @temp_cts_views where tablenickname = @tablenick)
  11497.                 return (1)
  11498.             
  11499.             select @ctsview = ctsvw from @temp_cts_views where tablenickname = @tablenick
  11500.             if @view_type <> 0
  11501.             begin
  11502.                 set @command_piece = 'create view dbo.' + @ctsview + 
  11503.                         ' as select * from dbo.MSmerge_contents where (tablenick = ' + @tablenickstr + ' and rowguid in
  11504.                         (select ' + @rowguidcolname + ' from ' + @view_name + ')) '
  11505.                 exec @retcode= dbo.sp_executesql @command_piece
  11506.                 if @@ERROR <>0 
  11507.                     return (1)
  11508.             end                    
  11509.             else
  11510.             begin
  11511.                 -- we get here if we find an unfiltered article in a publication which has some
  11512.                 -- subset filters
  11513.                 set @command_piece = 'create view dbo.' + @ctsview + 
  11514.                         ' as select * from dbo.MSmerge_contents 
  11515.                         where (tablenick = ' + @tablenickstr + ')'
  11516.                 exec @retcode= dbo.sp_executesql @command_piece
  11517.                 if @@ERROR <>0 
  11518.                     return (1)
  11519.             end
  11520.         end -- end @generate_per_article check
  11521.         
  11522.         /* Advance to next article and repeat the loop */
  11523.         select @tablenick = min(nickname) from sysmergearticles where
  11524.             pubid = @pubid and nickname > @tablenick and status<>@new_active and status<>@new_inactive
  11525.  
  11526.         /* make it so that any subsequent selects in the view are preceded by the word UNION */
  11527.         /* using OR to replace 'UNION ALL', which is equivalent to workaround a bug */
  11528.         set @or_after_first = ' OR '
  11529.     end
  11530.  
  11531. Finish:
  11532.     /* final steps: select out the text and drop the temp table */
  11533.     if @generate_per_article = 0
  11534.     begin
  11535.         select cmdtext from @tempcmd order by phase, step
  11536.     end         
  11537.     else
  11538.     begin
  11539.         /* Select the view names so that the caller can query them so they can be BCP'd out and dropped later */
  11540.         -- to see how this is read and used look at CMergePublication::GenerateContentsBcpFile
  11541.         select ctsvw from @temp_cts_views order by step
  11542.     end
  11543.  
  11544.     return(0)
  11545. go
  11546. exec dbo.sp_MS_marksystemobject sp_MSmakectsview 
  11547. go
  11548. grant exec on dbo.sp_MSmakectsview to public
  11549. go
  11550.  
  11551.  
  11552. --------------------------------------------------------------------------------
  11553. --. sp_MSmakesystableviews
  11554. -- performance optimization for zero rows in MSmerge_contents
  11555. --------------------------------------------------------------------------------
  11556. if exists (select * from sysobjects
  11557.     where type = 'P' and name = 'sp_MSmakesystableviews')
  11558. drop procedure sp_MSmakesystableviews
  11559. go
  11560. raiserror('Creating procedure sp_MSmakesystableviews', 0,1)
  11561. GO
  11562.  
  11563. -- Used by snapshot
  11564. create procedure sp_MSmakesystableviews (
  11565.     @publication sysname,
  11566.     @dynamic_snapshot_views_table_name sysname = null
  11567.     )
  11568. AS
  11569.     declare @guidstr         nvarchar(40)
  11570.     declare @pubid          uniqueidentifier
  11571.     declare @contentsview     sysname 
  11572.     declare @tombstoneview     sysname
  11573.     declare @genhistoryview    sysname
  11574.     declare @filtersview    sysname
  11575.     declare @piece            nvarchar(4000)
  11576.     declare @retcode smallint
  11577.     declare @dbname            sysname
  11578.     declare @art_count        int
  11579.     declare @skip_ctsv         int
  11580.     declare    @command        nvarchar(500)
  11581.     declare @dynamic_filters bit
  11582.     declare @view_creation_command nvarchar(4000)
  11583.     declare @newid          uniqueidentifier
  11584.  
  11585.     /*
  11586.     ** Check to see if current publication has permission
  11587.     */
  11588.     exec @retcode=sp_MSreplcheck_publish
  11589.     if @retcode<>0 or @@ERROR<>0 return (1)
  11590.     set @skip_ctsv = 0
  11591.     select @pubid = pubid, @dynamic_filters = dynamic_filters from sysmergepublications where name = @publication and UPPER(publisher)=UPPER(@@SERVERNAME) and publisher_db=db_name()
  11592.     if @pubid is null
  11593.         BEGIN
  11594.             RAISERROR (20026, 16, -1, @publication)
  11595.             RETURN (1)
  11596.         END
  11597.     select @art_count=count(*) from sysmergearticles where pubid=@pubid
  11598.     if @art_count > 253
  11599.         set @skip_ctsv=1
  11600.     select @newid = newid()
  11601.     create table #temp_table_for_systable_view(contentsview sysname, tombstoneview sysname NULL, genhistoryview sysname NULL, filtersview sysname NULL)
  11602.     exec @retcode = dbo.sp_MSguidtostr @newid, @guidstr out
  11603.     if @@ERROR<>0 OR @retcode<>0 return (1)
  11604.     select @contentsview = 'cont' + @guidstr
  11605.     select @tombstoneview = 'ts' + @guidstr
  11606.     select @genhistoryview = 'gh' + @guidstr
  11607.     select @filtersview = 'filt' + @guidstr
  11608.  
  11609.     set @guidstr = '''' + convert(nchar(36), @pubid) + ''''
  11610.     
  11611.     exec @retcode = dbo.sp_MSuniqueobjectname @tombstoneview, @tombstoneview out
  11612.     if @@ERROR<>0 OR @retcode<>0 return (1)
  11613.     exec @retcode = dbo.sp_MSuniqueobjectname @contentsview, @contentsview out
  11614.     if @@ERROR<>0 OR @retcode<>0 return (1)
  11615.     exec @retcode = dbo.sp_MSuniqueobjectname @genhistoryview, @genhistoryview out
  11616.     if @@ERROR<>0 OR @retcode<>0 return (1)
  11617.     exec @retcode = dbo.sp_MSuniqueobjectname @filtersview, @filtersview out
  11618.     if @@ERROR<>0 OR @retcode<>0 return (1)
  11619.     
  11620.     insert #temp_table_for_systable_view values(@contentsview,@tombstoneview,@genhistoryview,@filtersview)
  11621.  
  11622.         -- skip cts view if MSmerge_Contents contains zero rows
  11623.         if not exists (select * from MSmerge_contents)
  11624.             select @skip_ctsv = 1
  11625.         
  11626.     if @skip_ctsv = 0
  11627.     begin
  11628.         /* generate view for MSmerge_contents qualified by the pubid */
  11629.         /* For dynamically filtered publication, security check is performed in
  11630.            the sync view of the base table */
  11631.         set @command = 'sp_MSmakectsview ' + QUOTENAME(@publication) + ' , ' + @contentsview + ' , ' + COALESCE(QUOTENAME(@dynamic_snapshot_views_table_name) collate database_default, N'null' collate database_default) 
  11632.         set @dbname = db_name()
  11633.  
  11634.         exec @retcode = master..xp_execresultset @command, @dbname
  11635.         if @@ERROR<>0 OR @retcode <>0 
  11636.             return (1)
  11637.     end
  11638.     else
  11639.     begin
  11640.         exec('create view ' + @contentsview + ' as select * from MSmerge_contents where 1 = 2')
  11641.         if @@ERROR<>0
  11642.             return (1)
  11643.     end
  11644.     /* 
  11645.     ** generate the view for dbo.MSmerge_tombstone. In SP2 and Shiloh, the change was made to make the view 
  11646.     ** return 0 rows since it is unnecessary and expensive to propagate the tombstones.
  11647.     ** In order to leave all the other moving parts unchanged, we decided to let the view 
  11648.     ** return 0 rows.
  11649.     */
  11650.     select @view_creation_command = 'create view ' + @tombstoneview + ' as select * from dbo.MSmerge_tombstone where 1= 2 and
  11651.             tablenick in (select nickname from sysmergearticles where pubid = ' +
  11652.             @guidstr + ')'
  11653.  
  11654.     if @dynamic_filters = 1
  11655.     begin
  11656.         select @view_creation_command = @view_creation_command + ' and ((is_srvrolemember(''sysadmin'') = 1) or (is_member(''db_owner'') = 1) or (sessionproperty(''replication_agent'') = 1))'
  11657.     end
  11658.  
  11659.     exec (@view_creation_command)
  11660.     if @@ERROR <>0 
  11661.         begin
  11662.             return (1)
  11663.         end
  11664.  
  11665.     select @view_creation_command = 'create view ' + @genhistoryview + '(guidsrc, guidlocal, pubid, generation,
  11666.             art_nick, nicknames, coldate) as select DISTINCT guidsrc, guidlocal, CONVERT(uniqueidentifier, ' 
  11667.             + @guidstr + '), generation, art_nick, nicknames, coldate  from dbo.MSmerge_genhistory
  11668.             where guidlocal <> ''00000000-0000-0000-0000-000000000000'' and (art_nick = 0 or art_nick is NULL or
  11669.                     art_nick in (select nickname from sysmergearticles where pubid = ' +
  11670.             @guidstr + ')) '
  11671.     if @dynamic_filters = 1
  11672.     begin
  11673.         select @view_creation_command = @view_creation_command + ' and ((is_srvrolemember(''sysadmin'') = 1) or (is_member(''db_owner'') = 1) or (sessionproperty(''replication_agent'') = 1))'
  11674.     end
  11675.  
  11676.     exec (@view_creation_command)
  11677.     if @@ERROR <>0
  11678.         begin
  11679.             return (1)
  11680.         end
  11681.  
  11682.     select @view_creation_command = 'create view ' + @filtersview + ' as select * from sysmergesubsetfilters where pubid = ' +
  11683.             @guidstr
  11684.  
  11685.     if @dynamic_filters = 1
  11686.     begin
  11687.         select @view_creation_command = @view_creation_command + ' and ((is_srvrolemember(''sysadmin'') = 1) or (is_member(''db_owner'') = 1) or (sessionproperty(''replication_agent'') = 1))'
  11688.     end
  11689.  
  11690.     exec (@view_creation_command)
  11691.     if @@ERROR <>0
  11692.         begin
  11693.             return (1)
  11694.         end
  11695.  
  11696.     if @dynamic_filters = 1
  11697.     begin
  11698.         exec ('grant select on ' + @contentsview + ' to public')
  11699.         if @@error<>0 return(1)
  11700.         exec ('grant select on ' + @tombstoneview + ' to public')
  11701.         if @@error<>0 return(1)
  11702.         exec ('grant select on ' + @genhistoryview + ' to public')
  11703.         if @@error<>0 return(1)
  11704.         exec ('grant select on ' + @filtersview + ' to public')            
  11705.         if @@error<>0 return(1)
  11706.     end
  11707.  
  11708.     set nocount on
  11709.     /* we only generate per-article contents view for static publications */
  11710.     if @dynamic_filters=0
  11711.         begin
  11712.             exec @retcode = sp_MSgettablecontents @pubid
  11713.             if @@ERROR<>0 OR @retcode <>0 return (1)
  11714.          end
  11715.     exec('select * from #temp_table_for_systable_view ')
  11716.     drop table #temp_table_for_systable_view
  11717.  
  11718.     return (0)
  11719. go
  11720. exec dbo.sp_MS_marksystemobject sp_MSmakesystableviews
  11721. go
  11722. grant exec on dbo.sp_MSmakesystableviews to public
  11723. go
  11724.  
  11725.  
  11726. --------------------------------------------------------------------------------
  11727. --. sp_MSvalidate_agent_parameter
  11728. -- added the new parameter useperarticlecontentsview
  11729. --------------------------------------------------------------------------------
  11730. if exists (select * from sysobjects 
  11731.     where name = 'sp_MSvalidate_agent_parameter' 
  11732.             and type = 'P')
  11733.     drop procedure sp_MSvalidate_agent_parameter
  11734.  
  11735. raiserror('Creating procedure sp_MSvalidate_agent_parameter', 0,1)
  11736. go
  11737. create procedure sp_MSvalidate_agent_parameter (
  11738.     @profile_id      int,
  11739.     @parameter_name  sysname,
  11740.     @parameter_value nvarchar(255)
  11741. )
  11742. as
  11743.     declare @agent_type  int
  11744.     declare @original_parameter_name sysname
  11745.     declare @numeric_value int
  11746.  
  11747.     -- Make sure parameters are non-null
  11748.     if @profile_id is null
  11749.     BEGIN
  11750.         RAISERROR (14043, 16, -1, '@profile_id')
  11751.         RETURN (1)
  11752.     END
  11753.  
  11754.     if @parameter_name is null 
  11755.     BEGIN
  11756.         RAISERROR (14043, 16, -1, '@parameter_name')
  11757.         RETURN (1)
  11758.     END
  11759.  
  11760.     IF @parameter_value is null
  11761.     BEGIN
  11762.         RAISERROR (14043, 16, -1, '@parameter_value')
  11763.         RETURN (1)
  11764.     END
  11765.  
  11766.     select @original_parameter_name = @parameter_name
  11767.     
  11768.     select @agent_type = agent_type
  11769.     from msdb..MSagent_profiles 
  11770.     where profile_id = @profile_id
  11771.  
  11772.     -- Parameter name validation
  11773.     if (substring(@parameter_name, 1, 1) <> '/' and 
  11774.         substring(@parameter_name, 1, 1) <> '-')
  11775.     begin
  11776.         return 1
  11777.     end
  11778.  
  11779.     select @parameter_name = lower(substring(@parameter_name, 2, len(@parameter_name) - 1) collate SQL_Latin1_General_CP1_CS_AS)
  11780.  
  11781.     -- Snapshot agent - agent_type = 1
  11782.     if (@agent_type = 1)
  11783.     begin
  11784.         if not @parameter_name in ( 
  11785.             N'bcpbatchsize',   
  11786.             N'historyverboselevel',
  11787.             N'logintimeout',
  11788.             N'maxbcpthreads',
  11789.             N'querytimeout',
  11790.             N'startqueuetimeout',
  11791.             N'maxnetworkoptimization',
  11792.             N'useperarticlecontentsview'
  11793.             )    
  11794.         begin
  11795.             raiserror(21111, 16, -1, @original_parameter_name)
  11796.             return 1
  11797.         end
  11798.     end
  11799.     -- Logreader - agent_type = 2
  11800.     else if (@agent_type =2)  
  11801.     begin
  11802.         if not lower(@parameter_name collate SQL_Latin1_General_CP1_CS_AS) in ( 
  11803.             N'historyverboselevel',
  11804.             N'logintimeout',
  11805.             N'pollinginterval',
  11806.             N'querytimeout',
  11807.             N'readbatchsize'
  11808.             )    
  11809.         begin
  11810.             raiserror(21112, 16, -1, @original_parameter_name)
  11811.             return 1
  11812.         end
  11813.     end
  11814.     -- Distribution agent - agent_type = 3
  11815.     else if (@agent_type = 3)
  11816.     begin
  11817.         if not @parameter_name in ( 
  11818.             N'bcpbatchsize',   
  11819.             N'commitbatchsize',   
  11820.             N'commitbatchthreshold',   
  11821.             N'historyverboselevel',
  11822.             N'logintimeout',
  11823.             N'maxbcpthreads',
  11824.             N'maxdeliveredtransactions',
  11825.             N'pollinginterval',
  11826.             N'querytimeout',
  11827.             N'transactionsperhistory',
  11828.             N'skiperrors',
  11829.             N'keepalivemessageinterval',
  11830.             N'useinprocloader'            
  11831.             )    
  11832.         begin
  11833.             raiserror(21113, 16, -1, @original_parameter_name)
  11834.             return 1
  11835.         end
  11836.     end
  11837.     -- Merge agent - agent_type = 4
  11838.     else if (@agent_type = 4)
  11839.     begin 
  11840.         if not @parameter_name in ( 
  11841.             N'startqueuetimeout',
  11842.             N'pollinginterval',   
  11843.             N'validateinterval',   
  11844.             N'logintimeout',   
  11845.             N'querytimeout',
  11846.             N'maxuploadchanges',
  11847.             N'maxdownloadchanges',
  11848.             N'uploadgenerationsperbatch',   
  11849.             N'downloadgenerationsperbatch',   
  11850.             N'uploadreadchangesperbatch',   
  11851.             N'downloadreadchangesperbatch',   
  11852.             N'uploadwritechangesperbatch',
  11853.             N'downloadwritechangesperbatch',
  11854.             N'validate',   
  11855.             N'fastrowcount',   
  11856.             N'historyverboselevel',
  11857.             N'changesperhistory',
  11858.             N'bcpbatchsize',
  11859.             N'numdeadlockretries',
  11860.             N'keepalivemessageinterval',
  11861.             N'srcthreads',
  11862.             N'destthreads',
  11863.             N'useinprocloader',
  11864.             N'metadataretentioncleanup'
  11865.             )    
  11866.         begin
  11867.             raiserror(21114, 16, -1, @original_parameter_name)
  11868.             return 1
  11869.         end
  11870.     end
  11871.     -- Qreader agent - agent_type = 9
  11872.     else if (@agent_type = 9)  
  11873.     begin
  11874.         if not lower(@parameter_name collate SQL_Latin1_General_CP1_CS_AS) in ( 
  11875.             N'resolverstate',
  11876.             N'sqlqueuemode',
  11877.             N'historyverboselevel',
  11878.             N'pollinginterval',
  11879.             N'logintimeout',
  11880.             N'querytimeout'
  11881.             )    
  11882.         begin
  11883.             raiserror(21112, 16, -1, @original_parameter_name)
  11884.             return 1
  11885.         end
  11886.     end
  11887.     else if @agent_type is null
  11888.     begin
  11889.         raiserror (20066, 16, -1)   -- profile not defined
  11890.         return 1
  11891.     end
  11892.     else
  11893.     begin
  11894.         -- MSagent_parameters table corruption
  11895.         return 1
  11896.     end
  11897.  
  11898.     -- Parameter value validation
  11899.     if (@parameter_name = N'bcpbatchsize')
  11900.     begin
  11901.         select @numeric_value = convert(int, @parameter_value)
  11902.         if @@error <> 0 or @numeric_value < 1
  11903.         begin
  11904.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  11905.             return 1     
  11906.         end
  11907.     end
  11908.     else if (@parameter_name = N'commitbatchsize')
  11909.     begin
  11910.         select @numeric_value = convert(int, @parameter_value)
  11911.         if @@error <> 0 or @numeric_value < 1
  11912.         begin
  11913.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  11914.             return 1     
  11915.         end                        
  11916.     end
  11917.     else if (@parameter_name = N'commitbatchthreshold')
  11918.     begin
  11919.         select @numeric_value = convert(int, @parameter_value)
  11920.         if @@error <> 0 or @numeric_value < 1
  11921.         begin
  11922.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  11923.             return 1     
  11924.         end                        
  11925.     end
  11926.     else if (@parameter_name = N'downloadgenerationsperbatch')
  11927.     begin
  11928.         select @numeric_value = convert(int, @parameter_value)
  11929.         if @@error <> 0 or @numeric_value < 1
  11930.         begin
  11931.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  11932.             return 1     
  11933.         end 
  11934.         if @numeric_value > 2000
  11935.         begin
  11936.             raiserror(14266, 16, -1, 'DownloadGenerationsPerBatch', '1 - 2000') 
  11937.             return 1
  11938.         end                      
  11939.     end
  11940.     else if (@parameter_name = N'downloadreadchangesperbatch')
  11941.     begin
  11942.         select @numeric_value = convert(int, @parameter_value)
  11943.         if @@error <> 0 or @numeric_value < 1
  11944.         begin
  11945.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  11946.             return 1     
  11947.         end    
  11948.         if @numeric_value > 2000
  11949.         begin
  11950.             raiserror(14266, 16, -1, 'DownloadReadChangesPerBatch', '1 - 2000') 
  11951.             return 1
  11952.         end                      
  11953.     end
  11954.     else if (@parameter_name = N'downloadwritechangesperbatch')
  11955.     begin
  11956.         select @numeric_value = convert(int, @parameter_value)
  11957.         if @@error <> 0 or @numeric_value < 1
  11958.         begin
  11959.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  11960.             return 1     
  11961.         end 
  11962.         if @numeric_value > 2000
  11963.         begin
  11964.             raiserror(14266, 16, -1, 'DownloadWriteChangesPerBatch', '1 - 2000') 
  11965.             return 1
  11966.         end                         
  11967.     end
  11968.     else if (@parameter_name = N'fastrowcount')
  11969.     begin
  11970.         select @numeric_value = convert(int, @parameter_value)
  11971.         if @@error <> 0 or not (@numeric_value in (1,2,3))
  11972.         begin
  11973.             raiserror(21116, 16, -1, @parameter_value, @original_parameter_name)
  11974.             return 1     
  11975.         end                        
  11976.     end
  11977.     else if (@parameter_name = N'historyverboselevel')
  11978.     begin
  11979.         select @numeric_value = convert(int, @parameter_value)
  11980.         if @@error <> 0 or not (@numeric_value in (0,1,2,3))
  11981.         begin
  11982.             raiserror(21117, 16, -1, @parameter_value, @original_parameter_name)
  11983.             return 1     
  11984.         end                        
  11985.     end
  11986.     else if (@parameter_name = N'logintimeout')
  11987.     begin
  11988.         select @numeric_value = convert(int, @parameter_value)
  11989.         if @@error <> 0 or @numeric_value < 1
  11990.         begin
  11991.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  11992.             return 1     
  11993.         end                        
  11994.     end
  11995.     else if (@parameter_name = N'maxbcpthreads')
  11996.     begin
  11997.         select @numeric_value = convert(int, @parameter_value)
  11998.         if @@error <> 0 or @numeric_value < 1
  11999.         begin
  12000.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12001.             return 1     
  12002.         end                        
  12003.     end
  12004.     else if (@parameter_name = N'maxdeliveredtransactions')
  12005.     begin
  12006.         select @numeric_value = convert(int, @parameter_value)
  12007.         if @@error <> 0 or @numeric_value < 0
  12008.         begin
  12009.             raiserror(21119, 16, -1, @parameter_value, @original_parameter_name)
  12010.             return 1     
  12011.         end                        
  12012.     end
  12013.     else if (@parameter_name = N'pollinginterval')
  12014.     begin
  12015.         select @numeric_value = convert(int, @parameter_value)
  12016.         if @@error <> 0 or @numeric_value < 1
  12017.         begin
  12018.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12019.             return 1     
  12020.         end                        
  12021.     end
  12022.     else if (@parameter_name = N'querytimeout')
  12023.     begin
  12024.         select @numeric_value = convert(int, @parameter_value)
  12025.         if @@error <> 0 or @numeric_value < 1
  12026.         begin
  12027.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12028.             return 1     
  12029.         end                        
  12030.     end
  12031.     else if (@parameter_name = N'readbatchsize')
  12032.     begin
  12033.         select @numeric_value = convert(int, @parameter_value)
  12034.         if @@error <> 0 or @numeric_value < 1
  12035.         begin
  12036.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12037.             return 1     
  12038.         end                        
  12039.     end
  12040.     else if (@parameter_name = N'transactionsperhistory')
  12041.     begin
  12042.         select @numeric_value = convert(int, @parameter_value)
  12043.         if @@error <> 0 or @numeric_value not between 0 and 10000
  12044.         begin
  12045.             raiserror(211118, 16, -1, @parameter_value, @original_parameter_name)
  12046.             return 1     
  12047.         end                        
  12048.     end
  12049.     else if (@parameter_name = N'uploadgenerationsperbatch')
  12050.     begin
  12051.         select @numeric_value = convert(int, @parameter_value)
  12052.         if @@error <> 0 or @numeric_value < 1
  12053.         begin
  12054.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12055.             return 1     
  12056.         end 
  12057.         if @numeric_value > 2000
  12058.         begin
  12059.             raiserror(14266, 16, -1, 'UploadGenerationsPerBatch', '1 - 2000') 
  12060.             return 1
  12061.         end                         
  12062.     end
  12063.     else if (@parameter_name = N'uploadreadchangesperbatch')
  12064.     begin
  12065.         select @numeric_value = convert(int, @parameter_value)
  12066.         if @@error <> 0 or @numeric_value < 1
  12067.         begin
  12068.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12069.             return 1     
  12070.         end     
  12071.         if @numeric_value > 2000
  12072.         begin
  12073.             raiserror(14266, 16, -1, 'UploadReadChangesPerBatch', '1 - 2000') 
  12074.             return 1
  12075.         end                     
  12076.     end
  12077.     else if (@parameter_name = N'uploadwritechangesperbatch')
  12078.     begin
  12079.         select @numeric_value = convert(int, @parameter_value)
  12080.         if @@error <> 0 or @numeric_value < 1
  12081.         begin
  12082.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12083.             return 1     
  12084.         end 
  12085.         if @numeric_value > 2000
  12086.         begin
  12087.             raiserror(14266, 16, -1, 'UploadWriteChangesPerBatch', '1 - 2000') 
  12088.             return 1
  12089.         end                         
  12090.     end
  12091.     else if (@parameter_name = N'validate')
  12092.     begin
  12093.         select @numeric_value = convert(int, @parameter_value)
  12094.         if @@error <> 0 or not (@numeric_value in (0,1,2,3))
  12095.         begin
  12096.             raiserror(21117, 16, -1, @parameter_value, @original_parameter_name)
  12097.             return 1     
  12098.         end                        
  12099.     end
  12100.     else if (@parameter_name = N'validateinterval')
  12101.     begin
  12102.         select @numeric_value = convert(int, @parameter_value)
  12103.         if @@error <> 0 or @numeric_value < 1
  12104.         begin
  12105.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12106.             return 1     
  12107.         end                        
  12108.     end
  12109.     else if (@parameter_name = N'skiperrors')
  12110.     begin
  12111.         -- Empty string is valid.
  12112.         if @parameter_value <> N''
  12113.         begin
  12114.             -- Valid format: 11:22:33
  12115.             if    @parameter_value like '%[^0-9:]%' or
  12116.                 @parameter_value like ':%' or
  12117.                 @parameter_value like '%:' or
  12118.                 @parameter_value like '%::%'
  12119.             begin
  12120.                 raiserror(20601, 16, -1)
  12121.                 return 1
  12122.             end
  12123.             -- cannot has number of errors equals to or more than 11
  12124.             if    @parameter_value like '%:%:%:%:%:%:%:%:%:%:%'
  12125.             begin
  12126.                 raiserror(20602, 16, -1)
  12127.                 return 1
  12128.             end
  12129.         end
  12130.     end
  12131.     -- Parameter value validation
  12132.     else if (@parameter_name = N'numdeadlockretries')
  12133.     begin
  12134.         select @numeric_value = convert(int, @parameter_value)
  12135.         if @@error <> 0 or @numeric_value < 1
  12136.         begin
  12137.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12138.             return 1     
  12139.         end
  12140.         if @numeric_value > 100
  12141.         begin
  12142.             raiserror(14266, 16, -1, 'NumDeadlockRetries', '1 - 100') 
  12143.             return 1
  12144.         end                         
  12145.     end
  12146.     else if (@parameter_name = N'srcthreads')
  12147.     begin
  12148.         select @numeric_value = convert(int, @parameter_value)
  12149.         if @@error <> 0 or @numeric_value < 1
  12150.         begin
  12151.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12152.             return 1     
  12153.         end                        
  12154.     end
  12155.     else if (@parameter_name = N'destthreads')
  12156.     begin
  12157.         select @numeric_value = convert(int, @parameter_value)
  12158.         if @@error <> 0 or @numeric_value < 1
  12159.         begin
  12160.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12161.             return 1     
  12162.         end                        
  12163.     end
  12164.     else if (@parameter_name = N'keepalivemessageinterval')
  12165.     begin
  12166.         select @numeric_value = convert(int, @parameter_value)
  12167.         if @@error <> 0 or @numeric_value < 30
  12168.         begin
  12169.             raiserror(21405, 16, -1, @parameter_value, @original_parameter_name, 30)            
  12170.             return 1
  12171.         end
  12172.     end
  12173.     else if (@parameter_name = N'useinprocloader')
  12174.     begin
  12175.         select @numeric_value = convert(int, @parameter_value)
  12176.         if @@error <> 0 or @numeric_value not in (0, 1) or rtrim(@parameter_value) = N''
  12177.         begin
  12178.             raiserror(21406, 16, -1, @parameter_value, @original_parameter_name)
  12179.             return 1
  12180.         end
  12181.     end
  12182.     else if (@parameter_name = N'startqueuetimeout')
  12183.     begin
  12184.         select @numeric_value = convert(int, @parameter_value)
  12185.         if @@error <> 0 or (@numeric_value < 300 and @numeric_value <> 0) or rtrim(@parameter_value) = N''
  12186.         begin
  12187.             raiserror(21404, 16, -1, @parameter_value, @original_parameter_name)
  12188.             return 1
  12189.         end
  12190.     end
  12191.     else if (@parameter_name = N'resolverstate')
  12192.     begin
  12193.         select @numeric_value = convert(int, @parameter_value)
  12194.         if @@error <> 0 or @numeric_value not in (1,2,3)
  12195.         begin
  12196.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12197.             return 1     
  12198.         end                        
  12199.     end
  12200.     else if (@parameter_name = N'sqlqueuemode')
  12201.     begin
  12202.         select @numeric_value = convert(int, @parameter_value)
  12203.         if @@error <> 0 or @numeric_value not in (0,1,2)
  12204.         begin
  12205.             raiserror(21115, 16, -1, @parameter_value, @original_parameter_name)
  12206.             return 1     
  12207.         end                        
  12208.     end
  12209.     else if (@parameter_name = N'maxnetworkoptimization')
  12210.     begin
  12211.         select @numeric_value = convert(int, @parameter_value)
  12212.         if @@error <> 0 or @numeric_value not in (0, 1) or rtrim(@parameter_value) = N''
  12213.         begin
  12214.             raiserror(21406, 16, -1, @parameter_value, @original_parameter_name)
  12215.             return 1
  12216.         end
  12217.     end
  12218.     else if (@parameter_name = N'useperarticlecontentsview')
  12219.     begin
  12220.         select @numeric_value = convert(int, @parameter_value)
  12221.         if @@error <> 0 or @numeric_value not in (0, 1) or rtrim(@parameter_value) = N''
  12222.         begin
  12223.             raiserror(21406, 16, -1, @parameter_value, @original_parameter_name)
  12224.             return 1
  12225.         end
  12226.     end
  12227.     
  12228.     return 0
  12229. go 
  12230. EXEC dbo.sp_MS_marksystemobject 'sp_MSvalidate_agent_parameter'
  12231. go
  12232.  
  12233. -- Revoke privileges on mswebtasks and stored procedures
  12234. USE msdb
  12235. go
  12236. REVOKE INSERT ON mswebtasks FROM PUBLIC
  12237. go
  12238. REVOKE DELETE ON mswebtasks FROM PUBLIC
  12239. go
  12240. REVOKE UPDATE ON mswebtasks FROM PUBLIC
  12241. go
  12242. REVOKE EXECUTE ON sp_insmswebtask FROM PUBLIC
  12243. go
  12244. REVOKE EXECUTE ON sp_updmswebtask FROM PUBLIC
  12245. go
  12246.  
  12247. -- Revoke privileges on stored procedures
  12248. USE master
  12249. go
  12250. REVOKE EXECUTE ON sp_makewebtask FROM PUBLIC
  12251. go
  12252. REVOKE EXECUTE ON sp_dropwebtask FROM PUBLIC
  12253. go
  12254. REVOKE EXECUTE ON sp_cleanupwebtask FROM PUBLIC
  12255. go